From f0cb7669edc4d4285eb69754cf1ee53c6087af08 Mon Sep 17 00:00:00 2001 From: Damien Garros Date: Sat, 29 Nov 2025 16:38:22 +0100 Subject: [PATCH 1/3] docs: add and streamline AGENTS.md files for AI coding assistants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .vale/styles/spelling-exceptions.txt | 4 + AGENTS.md | 77 +++++++ CLAUDE.md | 317 +-------------------------- docs/AGENTS.md | 60 +++++ infrahub_sdk/ctl/AGENTS.md | 67 ++++++ infrahub_sdk/pytest_plugin/AGENTS.md | 67 ++++++ tests/AGENTS.md | 60 +++++ 7 files changed, 336 insertions(+), 316 deletions(-) create mode 100644 AGENTS.md create mode 100644 docs/AGENTS.md create mode 100644 infrahub_sdk/ctl/AGENTS.md create mode 100644 infrahub_sdk/pytest_plugin/AGENTS.md create mode 100644 tests/AGENTS.md diff --git a/.vale/styles/spelling-exceptions.txt b/.vale/styles/spelling-exceptions.txt index 904fc251..2da24e1f 100644 --- a/.vale/styles/spelling-exceptions.txt +++ b/.vale/styles/spelling-exceptions.txt @@ -20,9 +20,11 @@ Containerlab content_type convert_query_response coroutine +callouts cypher Dagster datastore +Diataxis default_branch default_filter deserialized @@ -42,6 +44,7 @@ eslint excalidraw fanout file_path +frontmatter generator_definition generator_definitions github @@ -114,6 +117,7 @@ template_path toml Towncrier towncrier +Typer uncheck uniqueness_constraints userinfo diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..186ae166 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,77 @@ +# AGENTS.md + +Infrahub Python SDK - async/sync client for Infrahub infrastructure management. + +## Commands + +```bash +uv sync --all-groups --all-extras # Install all deps +uv run invoke format # Format code +uv run invoke lint # Lint (ruff + mypy + yamllint) +uv run pytest tests/unit/ # Unit tests +uv run pytest tests/integration/ # Integration tests +``` + +## Tech Stack + +Python 3.9-3.13, UV, pydantic >=2.0, httpx, graphql-core + +## Code Pattern + +```python +# Always provide both async and sync versions +client = InfrahubClient() # async +client = InfrahubClientSync() # sync + +node = await client.get(kind="NetworkDevice") +await node.save() +``` + +## Project Structure + +```text +infrahub_sdk/ +├── client.py # Main client implementations +├── config.py # Pydantic configuration +├── node/ # Node system (core data model) +├── ctl/ # CLI (infrahubctl) +└── pytest_plugin/ # Custom pytest plugin +``` + +## Markdown Style + +When editing `.md` files, run `uv run invoke lint-docs` before committing. + +Key rules: + +- Use `text` language for directory structure code blocks +- Add blank lines before and after lists +- Always specify language in fenced code blocks (`python`, `bash`, `text`) + +## Boundaries + +✅ **Always** + +- Run `uv run invoke format lint` before committing Python code +- Run markdownlint before committing markdown changes +- Follow async/sync dual pattern for new features +- Use type hints on all function signatures + +⚠️ **Ask first** + +- Adding new dependencies +- Changing public API signatures + +🚫 **Never** + +- Push to GitHub automatically (always wait for user approval) +- Mix async/sync inappropriately +- Modify generated code (protocols.py) +- Bypass type checking without justification + +## Subdirectory Guides + +- [docs/AGENTS.md](docs/AGENTS.md) - Documentation (Docusaurus) +- [infrahub_sdk/ctl/AGENTS.md](infrahub_sdk/ctl/AGENTS.md) - CLI development +- [infrahub_sdk/pytest_plugin/AGENTS.md](infrahub_sdk/pytest_plugin/AGENTS.md) - Pytest plugin +- [tests/AGENTS.md](tests/AGENTS.md) - Testing diff --git a/CLAUDE.md b/CLAUDE.md index d00926da..302e76ef 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,317 +1,2 @@ -# CLAUDE.md -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Development Commands - -### Essential Commands - -```bash -# Install dependencies -uv sync --all-groups --all-extras - -# Install specific groups -uv sync --group tests # Testing dependencies only -uv sync --group lint # Linting dependencies only -uv sync --extra ctl # CLI dependencies only -uv sync --all-groups --all-extras # All optional dependencies - -# Format code -uv run invoke format - -# Run linting (ruff + mypy + yamllint + markdownlint) -uv run invoke lint - -# Run unit tests with coverage -uv run pytest --cov infrahub_sdk tests/unit/ - -# Run integration tests -uv run pytest tests/integration/ - -# Generate documentation -uv run invoke docs - -# Validate documentation -uv run invoke docs-validate -``` - -### Testing Specific Components - -```bash -# Run tests for specific modules -uv run pytest tests/unit/test_client.py -uv run pytest tests/unit/test_node.py - -# Run with verbose output -uv run pytest -v tests/unit/ - -# Run with parallel execution -uv run pytest -n 4 tests/unit/ -``` - -## Architecture Overview - -### Core Client Architecture - -- **Dual Client Pattern**: `InfrahubClient` (async) and `InfrahubClientSync` (sync) provide identical interfaces -- **Configuration**: Pydantic-based `Config` class with environment variable support -- **Transport**: HTTPX-based with proxy support (single proxy or HTTP/HTTPS mounts) -- **Authentication**: API tokens or JWT with automatic refresh - -### Key Modules Structure - -```text -infrahub_sdk/ -├── client.py # Main client implementations -├── config.py # Configuration management with Pydantic -├── node/ # Node system (core data model) -│ ├── node.py # InfrahubNode and InfrahubNodeSync -│ ├── attribute.py # Node attributes -│ └── relationship.py # Relationship management -├── ctl/ # CLI commands (infrahubctl) -├── pytest_plugin/ # Custom pytest plugin for Infrahub testing -└── protocols.py # Generated protocol classes -``` - -### Node System Design - -- **Lazy Loading**: Nodes load attributes and relationships on demand -- **Batch Operations**: Support for bulk create/update/delete operations -- **Relationship Management**: Automatic handling of node relationships with add/remove/replace operations -- **Validation**: Built-in data validation with GraphQL query generation - -## Infrahub-Specific Patterns - -### Checks Implementation - -```python -# CRITICAL: Use validate() method, NOT check() -class MyCheck(InfrahubCheck): - def validate(self, data): # Must be validate(), not check() - # validation logic - pass -``` - -### Async/Sync Pattern - -All operations follow dual implementation pattern: - -```python -# Async version (default) -client = InfrahubClient() -node = await client.get(kind="NetworkDevice") -await node.save() - -# Sync version -client = InfrahubClientSync() -node = client.get(kind="NetworkDevice") -node.save() -``` - -### Configuration Management - -- Environment variables prefixed with `INFRAHUB_` -- Proxy configuration: `INFRAHUB_PROXY` (single) or `INFRAHUB_PROXY_MOUNTS_HTTP`/`INFRAHUB_PROXY_MOUNTS_HTTPS` (separate) -- Mutual exclusivity validation between proxy configuration methods - -## Testing Framework - -### Custom Pytest Plugin - -The repository includes a custom pytest plugin (`infrahub_sdk.pytest_plugin`) that provides: - -- Fixtures for Infrahub clients and configuration -- Support for testing checks, transforms, and queries -- Integration with infrahub-testcontainers for Docker-based testing - -### Test Structure - -- **Unit Tests**: `tests/unit/` - Test individual components in isolation -- **Integration Tests**: `tests/integration/` - Test against real Infrahub instances -- **Coverage Target**: Maintained through codecov integration - -## CLI Architecture (`infrahubctl`) - -The CLI is built with Typer and provides extensive functionality: - -- **Schema Management**: Load, validate, and manage Infrahub schemas -- **Transformations**: Run Jinja2-based data transformations -- **Checks**: Execute validation checks against Infrahub data -- **Branch Operations**: Create, merge, and manage branches -- **Object Management**: CRUD operations on Infrahub objects - -CLI commands are auto-documented and organized in `infrahub_sdk/ctl/`. - -## Documentation System - -### Structure - -- **Docusaurus-based**: React/Node.js documentation system -- **Auto-generation**: CLI docs and config reference generated via invoke tasks -- **Multi-format**: Guides (task-oriented) and reference (API documentation) - -### Documentation Development - -```bash -# Generate all docs -uv run invoke docs - -# Start development server (requires Node.js) -cd docs && npm start -``` - -## Development Tooling - -### Code Quality - -- **Ruff**: Comprehensive linting and formatting (0.11.0) -- **mypy**: Type checking with strict configuration -- **yamllint**: YAML file validation -- **markdownlint**: Documentation consistency -- **Vale**: Documentation style checking - -### CI/CD Integration - -GitHub Actions workflow runs: - -1. Multi-version Python testing (3.10-3.13) -2. Comprehensive linting pipeline -3. Documentation generation and validation -4. Integration testing with Infrahub containers -5. Coverage reporting - -## Key Configuration Files - -- **pyproject.toml**: Poetry dependencies, tool configurations (ruff, mypy, pytest) -- **tasks.py**: Invoke task definitions for development workflows -- **.github/workflows/ci.yml**: Comprehensive CI/CD pipeline -- **docs/package.json**: Documentation build dependencies - -## Dependencies Management - -### Core Dependencies - -- **pydantic** (>=2.0.0): Configuration and data validation -- **httpx**: Async/sync HTTP client with proxy support -- **graphql-core**: GraphQL query building and parsing -- **ujson**: Fast JSON serialization - -### Optional Dependencies - -- **ctl extra**: CLI functionality (typer, rich, jinja2) -- **tests extra**: Testing framework extensions -- **all extra**: Complete development environment - -## Documentation Writing Guidelines - -When writing or modifying MDX documentation files in this repository, follow these established patterns: - -### Framework: Diataxis - -All documentation follows the [Diataxis framework](https://diataxis.fr/): - -- **Tutorials** (learning-oriented): Step-by-step learning experiences -- **How-to guides** (task-oriented): Problem-solving instructions -- **Explanation** (understanding-oriented): Clarification and discussion of topics -- **Reference** (information-oriented): Technical descriptions and specifications - -### Tone and Style - -- **Professional but approachable**: Use plain language with technical precision -- **Concise and direct**: Prefer short, active sentences with minimal fluff -- **Informative over promotional**: Focus on explaining how and why, not marketing -- **Consistent structure**: Follow predictable patterns across documents - -### Document Structure Patterns - -#### How-to Guides (Task-oriented) - -```markdown ---- -title: How to [accomplish specific task] ---- - -# Brief introduction stating the problem/goal - -## Prerequisites -- What the user needs before starting -- Required environment setup - -## Step-by-step Instructions - -### Step 1: [Action/Goal] -- Clear, actionable instructions -- Code snippets with proper language tags -- Screenshots/images for visual guidance -- Use Tabs for alternative methods (Web UI, GraphQL, Shell) - -### Step 2: [Next Action] -- Continue structured approach - -## Validation -- How to verify the solution worked -- Expected outputs and potential issues - -## Related Resources -- Links to related guides and topics -``` - -#### Topics (Understanding-oriented) - -```markdown ---- -title: Understanding [concept or feature] ---- - -# Introduction to what this explanation covers - -## Concepts & Definitions -- Key terms and how they fit into Infrahub - -## Background & Context -- Design decisions and rationale -- Technical constraints and considerations - -## Architecture & Design -- Diagrams and component interactions -- Mental models and analogies - -## Connections -- How this relates to other Infrahub concepts -- Integration points and relationships - -## Further Reading -- Links to guides, references, and external resources -``` - -### Content Guidelines - -#### For Guides - -- Use conditional imperatives: "If you want X, do Y" -- Address users directly: "Configure...", "Create...", "Deploy..." -- Focus on practical tasks without digressing into explanations -- Maintain focus on the specific goal - -#### For Topics - -- Use discursive, reflective tone that invites understanding -- Include context, background, and rationale behind design decisions -- Make connections between concepts and existing knowledge -- Present alternative perspectives where appropriate - -### Terminology and Quality - -- **Define new terms** when first introduced -- **Use domain-relevant language** from user perspective (playbooks, branches, schemas, commits) -- **Be consistent** with Infrahub's data model and UI naming conventions -- **Validate accuracy** against latest Infrahub version -- **Follow markdown style** as defined in `.markdownlint.yaml` and Vale styles in `.vale/styles/` - -### Code Examples and Formatting - -- Use proper language tags for all code blocks -- Include both async and sync examples where applicable using Tabs component -- Provide realistic examples that reflect real-world complexity -- Add validation steps to confirm success -- Use callouts for warnings, tips, and important notes \ No newline at end of file +@AGENTS.md diff --git a/docs/AGENTS.md b/docs/AGENTS.md new file mode 100644 index 00000000..36021cbb --- /dev/null +++ b/docs/AGENTS.md @@ -0,0 +1,60 @@ +# docs/AGENTS.md + +Docusaurus documentation following Diataxis framework. + +## Commands + +```bash +cd docs && npm install # Install deps +cd docs && npm start # Dev server at localhost:3000 +cd docs && npm run build # Build static site +uv run invoke docs # Generate auto-docs +uv run invoke docs-validate # Validate docs are current +``` + +## Structure + +```text +docs/docs/ +├── python-sdk/ +│ ├── guides/ # How-to guides (task-oriented) +│ ├── topics/ # Explanations (concept-oriented) +│ └── reference/ # API reference (auto-generated) +└── infrahubctl/ # CLI docs (auto-generated) +``` + +## Adding Documentation + +1. Create MDX file in appropriate directory +2. Add frontmatter with `title` +3. Update `sidebars-*.ts` for navigation + +## MDX Pattern + +Use Tabs for async/sync examples, callouts for notes: + +```mdx +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + ... + ... + + +:::warning +Use callouts for important notes. +::: +``` + +## Boundaries + +✅ **Always** + +- Include both async/sync examples using Tabs +- Run `uv run invoke docs-validate` after code changes + +🚫 **Never** + +- Edit `docs/infrahubctl/*.mdx` directly (regenerate with `uv run invoke generate-infrahubctl`) +- Edit `docs/python-sdk/reference/config.mdx` directly (regenerate with `uv run invoke generate-sdk`) diff --git a/infrahub_sdk/ctl/AGENTS.md b/infrahub_sdk/ctl/AGENTS.md new file mode 100644 index 00000000..545ad051 --- /dev/null +++ b/infrahub_sdk/ctl/AGENTS.md @@ -0,0 +1,67 @@ +# infrahub_sdk/ctl/AGENTS.md + +CLI tool (`infrahubctl`) built with Typer/AsyncTyper. + +## Command Pattern + +```python +from rich.console import Console +from ..async_typer import AsyncTyper +from ..ctl.client import initialize_client +from ..ctl.utils import catch_exception +from .parameters import CONFIG_PARAM + +console = Console() +app = AsyncTyper() + +@app.command(name="my-command") +@catch_exception(console=console) +async def my_command( + path: str = typer.Option(".", help="Path to file"), + branch: Optional[str] = None, + _: str = CONFIG_PARAM, # Always include, even if unused +): + client = initialize_client(branch=branch) + # implementation using Rich for output + console.print(Panel("Result", title="Success")) +``` + +## File Organization + +```text +infrahub_sdk/ctl/ +├── cli_commands.py # Entry point, registers subcommands +├── client.py # initialize_client(), initialize_client_sync() +├── utils.py # catch_exception decorator, parse_cli_vars +├── parameters.py # CONFIG_PARAM and shared parameters +├── branch.py # Branch subcommands +├── schema.py # Schema subcommands +└── object.py # Object subcommands +``` + +## Registering Commands + +```python +# In cli_commands.py +from ..ctl.branch import app as branch_app +app.add_typer(branch_app, name="branch") + +# Or for top-level commands +from .exporter import dump +app.command(name="dump")(dump) +``` + +## Boundaries + +✅ **Always** + +- Use `@catch_exception(console=console)` decorator +- Include `CONFIG_PARAM` in all commands +- Use `initialize_client()` for client creation +- Use Rich for output (tables, panels, console.print) + +🚫 **Never** + +- Use plain `print()` statements +- Instantiate `InfrahubClient` directly (use `initialize_client`) +- Forget error handling decorator diff --git a/infrahub_sdk/pytest_plugin/AGENTS.md b/infrahub_sdk/pytest_plugin/AGENTS.md new file mode 100644 index 00000000..1239d3a7 --- /dev/null +++ b/infrahub_sdk/pytest_plugin/AGENTS.md @@ -0,0 +1,67 @@ +# infrahub_sdk/pytest_plugin/AGENTS.md + +Custom pytest plugin for testing Infrahub resources via YAML test files. + +## YAML Test Format + +```yaml +infrahub_tests: + - resource: Check # Check, GraphQLQuery, Jinja2Transform, PythonTransform + resource_name: my_check + tests: + - name: test_success_case + spec: + kind: check-smoke # See test kinds below + input: + data: {...} + output: + passed: true +``` + +## Test Kinds + +| Resource | Smoke | Unit | Integration | +|----------|-------|------|-------------| +| Check | `check-smoke` | `check-unit-process` | `check-integration` | +| GraphQL | `graphql-query-smoke` | - | `graphql-query-integration` | +| Jinja2 | `jinja2-transform-smoke` | `jinja2-transform-unit-render` | `jinja2-transform-integration` | +| Python | `python-transform-smoke` | `python-transform-unit-process` | `python-transform-integration` | + +## Plugin Structure + +```text +infrahub_sdk/pytest_plugin/ +├── plugin.py # Pytest hooks (pytest_collect_file, etc.) +├── loader.py # YAML loading, ITEMS_MAPPING +├── models.py # Pydantic schemas for test files +└── items/ # Test item implementations + ├── base.py # InfrahubItem base class + └── check.py # Check-specific items +``` + +## Adding New Test Item + +```python +# 1. Create item class in items/ +class MyCustomItem(InfrahubItem): + def runtest(self): + result = self.process(self.test.input) + assert result == self.test.output + +# 2. Register in loader.py +ITEMS_MAPPING = { + "my-custom-test": MyCustomItem, + ... +} +``` + +## Boundaries + +✅ **Always** + +- Register new items in `ITEMS_MAPPING` +- Inherit from `InfrahubItem` base class + +🚫 **Never** + +- Forget to add new test kinds to `ITEMS_MAPPING` diff --git a/tests/AGENTS.md b/tests/AGENTS.md new file mode 100644 index 00000000..f3608ead --- /dev/null +++ b/tests/AGENTS.md @@ -0,0 +1,60 @@ +# tests/AGENTS.md + +pytest with async auto-mode enabled. + +## Commands + +```bash +uv run pytest tests/unit/ # Unit tests (fast, mocked) +uv run pytest tests/integration/ # Integration tests (real Infrahub) +uv run pytest -n 4 # Parallel execution +uv run pytest --cov infrahub_sdk # With coverage +uv run pytest tests/unit/test_client.py # Single file +``` + +## Structure + +```text +tests/ +├── unit/ # Fast, mocked, no external deps +├── integration/ # Real Infrahub via testcontainers +├── fixtures/ # Test data (JSON, YAML) +└── helpers/ # Test utilities +``` + +## Test Patterns + +```python +# Async test - NO decorator needed (auto mode) +async def test_async_operation(httpx_mock: HTTPXMock): + httpx_mock.add_response( + url="http://localhost:8000/api/graphql", + json={"data": {"result": "success"}}, + ) + client = InfrahubClient() + result = await client.execute(query="...") + assert result is not None + +# Sync test +def test_sync_operation(): + client = InfrahubClientSync() + # ... + +# CLI test +def test_cli_command(): + runner = CliRunner() + result = runner.invoke(app, ["command", "--flag"]) + assert result.exit_code == 0 +``` + +## Boundaries + +✅ **Always** + +- Use `httpx_mock` fixture for HTTP mocking +- Clean up resources in integration tests + +🚫 **Never** + +- Add `@pytest.mark.asyncio` (globally enabled) +- Make unit tests depend on external services From 50062ddd7ffe620d4c5bea8a3aca743b2bb244e9 Mon Sep 17 00:00:00 2001 From: Pete Crocker Date: Sat, 29 Nov 2025 19:22:23 +0000 Subject: [PATCH 2/3] Update Python version range in AGENTS.md --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 186ae166..2a0ae4cb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,7 +14,7 @@ uv run pytest tests/integration/ # Integration tests ## Tech Stack -Python 3.9-3.13, UV, pydantic >=2.0, httpx, graphql-core +Python 3.10-3.13, UV, pydantic >=2.0, httpx, graphql-core ## Code Pattern From acfeac090af255f27b107565eb540acd6b7c7839 Mon Sep 17 00:00:00 2001 From: Pete Crocker Date: Sat, 29 Nov 2025 19:23:09 +0000 Subject: [PATCH 3/3] Update linting instructions for markdown files --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 2a0ae4cb..fdc0e088 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -40,7 +40,7 @@ infrahub_sdk/ ## Markdown Style -When editing `.md` files, run `uv run invoke lint-docs` before committing. +When editing `.md` or `.mdx` files, run `uv run invoke lint-docs` before committing. Key rules: