|
1 | | -# QBO CLI — Agent Instructions |
| 1 | +# Agent Guidelines for Python Code Quality |
2 | 2 |
|
3 | | -QuickBooks Online CLI tool for accounting operations. |
| 3 | +This document provides guidelines for maintaining high-quality Python code. These rules MUST be followed by all AI coding agents and contributors. |
| 4 | + |
| 5 | +## Your Core Principles |
| 6 | + |
| 7 | +All code you write MUST be fully optimized. |
| 8 | + |
| 9 | +"Fully optimized" includes: |
| 10 | + |
| 11 | +- maximizing algorithmic big-O efficiency for memory and runtime |
| 12 | +- using parallelization and vectorization where appropriate |
| 13 | +- following proper style conventions for the code language (e.g. maximizing code reuse (DRY)) |
| 14 | +- no extra code beyond what is absolutely necessary to solve the problem the user provides (i.e. no technical debt) |
| 15 | + - If a Python library can be imported to significantly reduce the amount of new code required to implement a function at optimal performance, and the library itself is small and does not have much overhead, ALWAYS use the library instead. |
| 16 | + |
| 17 | +If the code is not fully optimized before handing off to the user, you will be fined $100. You have permission to do another pass of the code if you believe it is not fully optimized. |
| 18 | + |
| 19 | +## Preferred Tools |
| 20 | + |
| 21 | +- Use `uv` for Python package management and to create a `.venv` if it is not present. |
| 22 | +- Ensure `ipykernel` and `ipywidgets` is installed in `.venv` for Jupyter Notebook compatability. This should not be in package requirements. |
| 23 | +- Use `tqdm` to track long-running loops within Jupyter Notebooks. The `description` of the progress bar should be contextually sensitive. |
| 24 | +- Use `orjson` for JSON loading/dumping. |
| 25 | +- When reporting error to the console, use `logger.error` instead of `print`. |
| 26 | +- If the project involves the creation of images (e.g. PNG/WEBP), you have permission to use the Read tool to verify the rendered images fit the user and application requirements. |
| 27 | +- For data science: |
| 28 | + - **ALWAYS** use `polars` instead of `pandas` for data frame manipulation. |
| 29 | + - If a `polars` dataframe will be printed, **NEVER** simultaneously print the number of entries in the dataframe nor the schema as it is redundant. |
| 30 | + - **NEVER** ingest more than 10 rows of a data frame at a time. Only analyze subsets of code to avoid overloading your memory context. |
| 31 | +- For creating databases: |
| 32 | + - Do not denormalized unless explicitly prompted to do so. |
| 33 | + - Always use the most appropriate datatype, such as `DATETIME/TIMESTAMP` for datetime-related fields. |
| 34 | + - Use `ARRAY` datatypes for nested fields. **NEVER** save as `TEXT/STRING`. |
| 35 | +- In Jupyter Notebooks, DataFrame objects within conditional blocks should be explicitly `print()` as they will not be printed automatically. |
| 36 | + |
| 37 | +## Code Style and Formatting |
| 38 | + |
| 39 | +- **MUST** use meaningful, descriptive variable and function names |
| 40 | +- **MUST** follow PEP 8 style guidelines |
| 41 | +- **MUST** use 4 spaces for indentation (never tabs) |
| 42 | +- **NEVER** use emoji, or unicode that emulates emoji (e.g. ✓, ✗). The only exception is when writing tests and testing the impact of multibyte characters. |
| 43 | +- Use snake_case for functions/variables, PascalCase for classes, UPPER_CASE for constants |
| 44 | +- Limit line length to 88 characters (ruff formatter standard) |
| 45 | +- **MUST** avoid including redundant comments which are tautological or self-demonstating (e.g. cases where it is easily parsable what the code does at a glance so the comment does) |
| 46 | +- **MUST** avoid including comments which leak what this file contains, or leak the original user prompt, ESPECIALLY if it's irrelevant to the output code. |
| 47 | + |
| 48 | +## Documentation |
| 49 | + |
| 50 | +- **MUST** include docstrings for all public functions, classes, and methods |
| 51 | +- **MUST** document function parameters, return values, and exceptions raised |
| 52 | +- Keep comments up-to-date with code changes |
| 53 | +- Include examples in docstrings for complex functions |
| 54 | + |
| 55 | +Example docstring: |
| 56 | + |
| 57 | +```python |
| 58 | +def calculate_total(items: list[dict], tax_rate: float = 0.0) -> float: |
| 59 | + """Calculate the total cost of items including tax. |
| 60 | +
|
| 61 | + Args: |
| 62 | + items: List of item dictionaries with 'price' keys |
| 63 | + tax_rate: Tax rate as decimal (e.g., 0.08 for 8%) |
| 64 | +
|
| 65 | + Returns: |
| 66 | + Total cost including tax |
| 67 | +
|
| 68 | + Raises: |
| 69 | + ValueError: If items is empty or tax_rate is negative |
| 70 | + """ |
| 71 | +``` |
| 72 | + |
| 73 | +## Type Hints |
| 74 | + |
| 75 | +- **MUST** use type hints for all function signatures (parameters and return values) |
| 76 | +- **NEVER** use `Any` type unless absolutely necessary |
| 77 | +- **MUST** run mypy and resolve all type errors |
| 78 | +- Use `Optional[T]` or `T | None` for nullable types |
| 79 | + |
| 80 | +## Error Handling |
| 81 | + |
| 82 | +- **NEVER** silently swallow exceptions without logging |
| 83 | +- **MUST** never use bare `except:` clauses |
| 84 | +- **MUST** catch specific exceptions rather than broad exception types |
| 85 | +- **MUST** use context managers (`with` statements) for resource cleanup |
| 86 | +- Provide meaningful error messages |
| 87 | + |
| 88 | +## Function Design |
| 89 | + |
| 90 | +- **MUST** keep functions focused on a single responsibility |
| 91 | +- **NEVER** use mutable objects (lists, dicts) as default argument values |
| 92 | +- Limit function parameters to 5 or fewer |
| 93 | +- Return early to reduce nesting |
| 94 | + |
| 95 | +## Class Design |
| 96 | + |
| 97 | +- **MUST** keep classes focused on a single responsibility |
| 98 | +- **MUST** keep `__init__` simple; avoid complex logic |
| 99 | +- Use dataclasses for simple data containers |
| 100 | +- Prefer composition over inheritance |
| 101 | +- Avoid creating additional class functions if they are not necessary |
| 102 | +- Use `@property` for computed attributes |
| 103 | + |
| 104 | +## Testing |
| 105 | + |
| 106 | +- **MUST** write unit tests for all new functions and classes |
| 107 | +- **MUST** mock external dependencies (APIs, databases, file systems) |
| 108 | +- **MUST** use pytest as the testing framework |
| 109 | +- **NEVER** run tests you generate without first saving them as their own discrete file |
| 110 | +- **NEVER** delete files created as a part of testing. |
| 111 | +- Ensure the folder used for test outputs is present in `.gitignore` |
| 112 | +- Follow the Arrange-Act-Assert pattern |
| 113 | +- Do not commit commented-out tests |
| 114 | + |
| 115 | +## Imports and Dependencies |
| 116 | + |
| 117 | +- **MUST** avoid wildcard imports (`from module import *`) |
| 118 | +- **MUST** document dependencies in `pyproject.toml` |
| 119 | +- Use `uv` for fast package management and dependency resolution |
| 120 | +- Organize imports: standard library, third-party, local imports |
| 121 | +- Use `isort` to automate import formatting |
| 122 | + |
| 123 | +## Python Best Practices |
| 124 | + |
| 125 | +- **NEVER** use mutable default arguments |
| 126 | +- **MUST** use context managers (`with` statement) for file/resource management |
| 127 | +- **MUST** use `is` for comparing with `None`, `True`, `False` |
| 128 | +- **MUST** use f-strings for string formatting |
| 129 | +- Use list comprehensions and generator expressions |
| 130 | +- Use `enumerate()` instead of manual counter variables |
| 131 | + |
| 132 | +## Benchmarking and Optimization |
| 133 | + |
| 134 | +- **NEVER** run benchmarks in parallel, as the benchmarks will compete for resources and the results will be invalid |
| 135 | +- **NEVER** game the benchmarks. Do not manipulate the benchmarks themselves to satisfy any required performance constraints |
| 136 | +- If benchmarking against another crate or library, ensure the benchmarks are apples-to-apples comparisons |
| 137 | +- Ensure benchmark tests are independent. If the tests are dependent due to a feature (e.g. caching), ensure the feature is disabled |
| 138 | + |
| 139 | +## Security |
| 140 | + |
| 141 | +- **NEVER** store secrets, API keys, or passwords in code. Only store them in `.env` |
| 142 | + - Ensure `.env` is declared in `.gitignore`. |
| 143 | + - **NEVER** print or log URLs to console if they contain an API key |
| 144 | +- **MUST** use environment variables for sensitive configuration |
| 145 | +- **NEVER** log sensitive information (passwords, tokens, PII) |
| 146 | + |
| 147 | +## Version Control |
| 148 | + |
| 149 | +- **MUST** write clear, descriptive commit messages |
| 150 | +- **NEVER** commit commented-out code; delete it |
| 151 | +- **NEVER** commit debug print statements or breakpoints |
| 152 | +- **NEVER** commit credentials or sensitive data |
| 153 | + |
| 154 | +## Tools |
| 155 | + |
| 156 | +- **MUST** use Ruff for code formatting and linting (replaces Black, isort, flake8) |
| 157 | +- **MUST** use mypy for static type checking |
| 158 | +- Use `uv` for package management (faster alternative to pip) |
| 159 | +- Use pytest for testing |
| 160 | + |
| 161 | +## Before Committing |
| 162 | + |
| 163 | +- [ ] All tests pass |
| 164 | +- [ ] Type checking passes (mypy) |
| 165 | +- [ ] Code formatter and linter pass (Ruff) |
| 166 | +- [ ] All functions have docstrings and type hints |
| 167 | +- [ ] No commented-out code or debug statements |
| 168 | +- [ ] No hardcoded credentials |
| 169 | + |
| 170 | +--- |
| 171 | + |
| 172 | +**Remember:** Prioritize clarity and maintainability over cleverness. This is your core directive. |
0 commit comments