Skip to content

[Docs]: Create XML-tagged Copilot Instructions for Code Generation Guidelines #12

@Harmeet10000

Description

@Harmeet10000

Type of Documentation Issue

Missing Documentation

Location

    The existing `.github/copilot-instructions.md` file. This issue proposes replacing it with a new, structured XML file.

Description

We need to replace the existing copilot-instructions.md with a new copilot-instructions.xml file. This new file will contain comprehensive, XML-tagged instructions designed to guide GitHub Copilot in generating code that strictly adheres to our project's specific development standards and best practices.

The current markdown file is less structured and might not be as effective in guiding an AI assistant as a clearly defined, XML-based instruction set. The goal is to provide Copilot with a precise and machine-readable guide to ensure consistency and quality in generated code, minimizing manual review and refactoring.

Suggested Changes

The new copilot-instructions.xml file should encompass the following key areas, structured with appropriate XML tags for clarity and machine readability:

Overall Structure:

  • A root XML tag, e.g., <CopilotInstructions>.
  • Sections for different categories of guidelines.

Core Development Principles:

  • Language: Python 3.12 (<Language>Python 3.12</Language>)
  • Style: Functional programming, immutability, DRY (Don't Repeat Yourself), KISS (Keep It Simple, Stupid). (<Style>, <Principle>...</Principle>)
  • Tooling: Explicitly mention uv commands for package management and virtual environments. (<Tooling>, <Command>uv install</Command>, etc.)

Code Formatting & Typing:

  • Formatting: Black and isort compliance. (<Formatting>, <Tool>Black</Tool>, <Tool>isort</Tool>)
  • Typing: Strict mypy suggestions, favoring TypedDict and dataclasses for data structures. (<Typing>, <Tool>mypy</Tool>, <Recommendation>TypedDict</Recommendation>)

FastAPI Best Practices:

  • Structure: APIRouter per feature. (<FastAPIBestPractices>, <Structure>APIRouter-per-feature</Structure>)
  • Dependencies: Injection via Depends. (<DependencyInjection>FastAPI.Depends</DependencyInjection>)
  • Lifecycle: lifespan/startup for I/O and resource initialization. (<Lifecycle>lifespan/startup</Lifecycle>)
  • Data Models: Pydantic guidance for request/response models. (<DataModels>Pydantic</DataModels>)
  • Concurrency: Async-first approach. (<Concurrency>async-first</Concurrency>)
  • Error Handling: Centralized error handling in middleware. (<ErrorHandling>middleware</ErrorHandling>)

Design Patterns:

  • Factory Pattern: For configuring clients (e.g., database connections, external APIs). (<DesignPattern>, <PatternType>Factory</PatternType>)
  • Adapter Pattern: For wrapping third-party clients to ensure a consistent interface. (<PatternType>Adapter</PatternType>)
  • Pure Functions: Emphasis on small, pure functions where possible. (<DesignPattern>, <PatternType>PureFunctions</PatternType>)
  • Dependency Injection: General principle. (<DesignPattern>, <PatternType>DependencyInjection</PatternType>)

Examples (within CDATA sections to avoid XML parsing issues by Copilot):

  • A small FastAPI endpoint wiring example.
  • Snippets demonstrating Factory and Adapter patterns.

CI Suggestions:

  • Run black, isort, mypy, and pytest in CI/CD pipelines. (<CISuggestions>, <Tool>black</Tool>)

Anti-Patterns / Do-Nots:

  • No I/O at import time. (<AntiPattern>No_IO_at_import</AntiPattern>)
  • No global mutable singletons. (<AntiPattern>No_Global_Mutable_Singletons</AntiPattern>)
  • Avoid deep class hierarchies. (<AntiPattern>Avoid_Deep_Class_Hierarchies</AntiPattern>)

Example XML Structure Snippet:

        <CopilotInstructions>
          <General>
            <Language>Python 3.12</Language>
            <Style>
              <Principle>Functional Programming</Principle>
              <Principle>Immutability</Principle>
              <Principle>DRY (Don't Repeat Yourself)</Principle>
              <Principle>KISS (Keep It Simple, Stupid)</Principle>
            </Style>
            <Tooling>
              <Description>Always use 'uv' commands for package management and virtual environments.</Description>
              <Command>uv install</Command>
              <Command>uv run</Command>
              <!-- Add other common uv commands -->
            </Tooling>
          </General>

          <CodeQuality>
            <Formatting>
              <Tool>Black</Tool>
              <Tool>isort</Tool>
              <Guidance>Ensure generated code adheres to Black's formatting rules.</Guidance>
              <Guidance>Ensure imports are sorted and grouped by isort's rules.</Guidance>
            </Formatting>
            <Typing>
              <Tool>mypy</Tool>
              <Guidance>Use strict type hints for all functions, variables, and arguments.</Guidance>
              <Recommendation>Favor `typing.TypedDict` for simple dictionaries with fixed keys and types.</Recommendation>
              <Recommendation>Favor `dataclasses` for simple data objects.</Recommendation>
            </Typing>
          </CodeQuality>

          <FastAPIBestPractices>
            <Structure>
              <Pattern>Use `fastapi.APIRouter` for organizing routes by feature or domain.</Pattern>
            </Structure>
            <DependencyInjection>
              <Mechanism>Use `fastapi.Depends` for dependency injection.</Mechanism>
              <Guidance>Inject configured clients, repositories, and services using `Depends`.</Guidance>
            </DependencyInjection>
            <Lifecycle>
              <Event>Use `lifespan` (FastAPI 0.100+) or `startup` (older FastAPI) events for I/O and resource initialization.</Event>
            </Lifecycle>
            <DataModels>
              <Tool>Pydantic</Tool>
              <Guidance>Define request and response body schemas using Pydantic `BaseModel`.</Guidance>
              <Guidance>Use Pydantic for data validation and serialization.</Guidance>
            </DataModels>
            <Concurrency>
              <Principle>Design API endpoints and internal functions to be `async` where I/O operations are involved.</Principle>
            </Concurrency>
            <ErrorHandling>
              <Mechanism>Centralized error handling via FastAPI middleware or custom exception handlers.</Mechanism>
            </ErrorHandling>
          </FastAPIBestPractices>

          <DesignPatterns>
            <Pattern type="Factory">
              <Description>Use the Factory pattern for creating and configuring external clients (e.g., database, API clients, LLM providers).</Description>
              <Example><![CDATA[
                from httpx import AsyncClient

                def create_http_client(base_url: str) -> AsyncClient:
                    return AsyncClient(base_url=base_url, timeout=5.0)

                # Usage via Depends in FastAPI
                # async def get_client(client: AsyncClient = Depends(lambda: create_http_client("https://api.example.com"))):
                #     ...
              ]]></Example>
            </Pattern>
            <Pattern type="Adapter">
              <Description>Use the Adapter pattern to wrap third-party client libraries, providing a consistent, internal interface.</Description>
              <Example><![CDATA[
                # Original third-party client
                class ExternalService:
                    def fetch_data_legacy(self, param1: str) -> dict:
                        ...

                # Our adapter
                class ExternalServiceAdapter:
                    def __init__(self, client: ExternalService):
                        self._client = client

                    def get_info(self, identifier: str) -> dict:
                        # Translate our interface to the third-party client's interface
                        return self._client.fetch_data_legacy(param1=identifier)
              ]]></Example>
            </Pattern>
            <Pattern type="PureFunctions">
              <Description>Prefer small, self-contained, pure functions (no side effects, deterministic output for given input).</Description>
            </Pattern>
            <Pattern type="DependencyInjection">
              <Description>Favor dependency injection over global state or hardcoded dependencies.</Description>
            </Pattern>
          </DesignPatterns>

          <Examples>
            <Example type="FastAPIEndpoint"><![CDATA[
              from fastapi import APIRouter, Depends, HTTPException, status
              from pydantic import BaseModel

              router = APIRouter(prefix="/items", tags=["items"])

              class Item(BaseModel):
                  id: str
                  name: str
                  description: str | None = None

              class ItemCreate(BaseModel):
                  name: str
                  description: str | None = None

              # Assume an in-memory db for simplicity, replace with real db client injected via Depends
              _items_db: dict[str, Item] = {}

              @router.post("/", response_model=Item, status_code=status.HTTP_201_CREATED)
              async def create_item(item_data: ItemCreate) -> Item:
                  new_id = f"item-{len(_items_db) + 1}" # In real app, use UUID
                  new_item = Item(id=new_id, **item_data.model_dump())
                  _items_db[new_id] = new_item
                  return new_item

              @router.get("/{item_id}", response_model=Item)
              async def read_item(item_id: str) -> Item:
                  item = _items_db.get(item_id)
                  if not item:
                      raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Item not found")
                  return item
            ]]></Example>
          </Examples>

          <CISuggestions>
            <Tool>black</Tool>
            <Tool>isort</Tool>
            <Tool>mypy</Tool>
            <Tool>pytest</Tool>
            <Guidance>Ensure these tools are run in CI/CD pipelines to enforce code quality.</Guidance>
          </CISuggestions>

          <AntiPatterns>
            <Pattern>
              <Name>No I/O at import time</Name>
              <Reason>Avoid side effects when modules are imported to ensure predictable startup and testability.</Reason>
            </Pattern>
            <Pattern>
              <Name>No global mutable singletons</Name>
              <Reason>Leads to hard-to-test code, side effects, and concurrency issues. Prefer dependency injection.</Reason>
            </Pattern>
            <Pattern>
              <Name>Avoid deep class hierarchies</Name>
              <Reason>Favors composition over inheritance. Deep hierarchies can lead to rigid designs and the "Yo-yo problem".</Reason>
            </Pattern>
          </AntiPatterns>
        </CopilotInstructions>

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions