Skip to content

Commit cde6efa

Browse files
committed
Optional agent instructions
1 parent 7ad701f commit cde6efa

File tree

4 files changed

+135
-1
lines changed

4 files changed

+135
-1
lines changed

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Rob's Awesome Python Template is extremely customizable- it can work for the sma
55
- [Rob's Awesome Python Template](#robs-awesome-python-template)
66
- [Usage](#usage)
77
- [Core Functionality](#core-functionality)
8-
- [Optional Libraries](#optional-libraries)
8+
- [Optional Functionality](#optional-libraries)
99
- [FastAPI](#fastapi)
1010
- [Celery](#celery)
1111
- [QuasiQueue](#quasiqueue)
@@ -14,6 +14,7 @@ Rob's Awesome Python Template is extremely customizable- it can work for the sma
1414
- [Paracelsus](#paracelsus)
1515
- [Docker](#docker)
1616
- [Github Actions](#github-actions)
17+
- [Agentic Instructions](#agentic-instructions)
1718
- [Examples](#examples)
1819

1920

@@ -95,6 +96,10 @@ Github Action Workflows are optionally created for a variety of tasks-
9596
- Updating Dependency (requirements.txt) Files
9697
- Updating Documentation
9798

99+
### Agentic Instructions
100+
101+
A predefined AGENTS.md file enables project specific instructions and best practices for coding agents such as Github Copilot, Cursor, and Windsurf.
102+
98103
## Examples
99104

100105
Project examples are available in the [example repository](https://github.com/tedivm/robs_awesome_python_template_examples).

cookiecutter.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"include_docker": "y/N",
2121
"include_github_actions": "y/N",
2222
"include_requirements_files": "y/N",
23+
"include_agents_instructions": "y/N",
2324
"publish_to_pypi": "y/N",
2425
"__package_slug": "{{ cookiecutter.package_name.lower().replace(' ', '_').replace('-', '_') }}",
2526
"__python_short_version": "{{ cookiecutter.python_version.split('.')[:2]|join('.') }}"

hooks/post_gen_project.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
INCLUDE_SQLALCHEMY={% if cookiecutter.include_sqlalchemy == "y" %}True{% else %}False{% endif %}
1515
INCLUDE_GITHUB_ACTIONS={% if cookiecutter.include_github_actions == "y" %}True{% else %}False{% endif %}
1616
INCLUDE_REQUIREMENTS_FILES={% if cookiecutter.include_requirements_files == "y" %}True{% else %}False{% endif %}
17+
INCLUDE_AGENT_INSTRUCTIONS={% if cookiecutter.include_agents_instructions == "y" %}True{% else %}False{% endif %}
1718
PUBLISH_TO_PYPI={% if cookiecutter.publish_to_pypi == "y" %}True{% else %}False{% endif %}
1819
PACKAGE_SLUG="{{cookiecutter.__package_slug}}"
1920

@@ -88,6 +89,9 @@
8889
remove_paths.add('.github/workflows/lockfiles.yaml')
8990
remove_paths.add(f'docs/dev/dependencies.md')
9091

92+
if not INCLUDE_AGENT_INSTRUCTIONS:
93+
remove_paths.add(f'AGENTS.md')
94+
9195
for path in remove_paths:
9296
path = path.strip()
9397
if path and os.path.exists(path):
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# Agent Instructions
2+
3+
You should always follow the best practices outlined in this document. If there is a valid reason why you cannot follow one of these practices, you should inform the user and document the reasons.
4+
5+
Before beginning any task, make sure you review the documentation (`docs/dev/` and `README.md`), the existing tests to understand the project, and the task runner (Makefile) to understand what dev tools are available and how to use them. You should review code related to your request to understand preferred style: for example, you should review other tests before writing a new test suite, or review existing routers before creating a new one.
6+
7+
## Best Practices
8+
9+
### General
10+
11+
* Assume the minimum version of Python is 3.10.
12+
* Prefer async libraries and functions over synchronous ones.
13+
* Always define dependencies and tool settings in `pyproject.toml`: never use `setup.py` or `setup.cfg` files.
14+
* Prefer existing dependencies over adding new ones when possible.
15+
* For complex code, always consider using third-party libraries instead of writing new code that has to be maintained.
16+
* Use keyword arguments instead of positional arguments when calling functions and methods.
17+
* Do not put `import` statements inside functions unless necessary to prevent circular imports. Imports should be at the top of the file.
18+
19+
### Security
20+
21+
* Always write secure code.
22+
* Never hardcode sensitive data.
23+
* Do not log sensitive data.
24+
* All user input should be validated.
25+
26+
### Production Ready
27+
28+
* All generated code should be production ready.
29+
* There should be no stubs "for production".
30+
* There should not be any non-production logic branches in the main code package itself.
31+
* Any code or package differences between Development and Production should be avoided unless absolutely necessary.
32+
33+
### Logging
34+
35+
* Do not use `print` for logging or debugging: use the `getLogger` logger instead.
36+
* Each file should get its own logger using the `__name__` variable for a name.
37+
* Use logging levels to allow developers to enable richer logging while testing than in production.
38+
* Most caught exceptions should be logged with `logger.exception`.
39+
40+
### Commenting
41+
42+
* Comments should improve code readability and understandability.
43+
* Comments should not simply exist for the sake of existing.
44+
* Examples of good comments include unclear function names/parameters, decisions about settings or function choices, logic descriptions, variable definitions, security risks, edge cases, and advice for developers refactoring or expanding code.
45+
* Comments should be concise, accurate, and add value to the codebase.
46+
47+
### Error Handling
48+
49+
* Do not suppress exceptions unless expected, and handle them properly when suppressing.
50+
* When suppressing exceptions, log them using `logger.exception`.
51+
52+
### Typing
53+
54+
* Everything should be typed: function signatures (including return values), variables, and anything else.
55+
* Use the union operator for multiple allowed types.
56+
* Do not use `Optional`: use a union with `None` (i.e., `str | None`).
57+
* Use typing library metaclasses instead of native types for objects and lists (i.e., `Dict[str, str]` and `List[str]` instead of `dict` or `list`).
58+
* Avoid using `Any` unless absolutely necessary.
59+
* If the schema is defined, use a `dataclass` with properly typed parameters instead of a `dict`.
60+
61+
### Settings
62+
63+
* Manage application settings with the `pydantic-settings` library.
64+
* Sensitive configuration data should always use Pydantic `SecretStr` or `SecretBytes` types.
65+
* Settings that are allowed to be unset should default to `None` instead of empty strings.
66+
* Define settings with the Pydantic `Field` function and include descriptions for users.
67+
68+
{%- if cookiecutter.include_fastapi == "y" %}
69+
70+
### FastAPI
71+
72+
* APIs should adhere as closely as possible to REST principles, including appropriate use of GET/PUT/POST/DELETE HTTP verbs.
73+
* All routes should use Pydantic models for input and output.
74+
* Use different Pydantic models for inputs and outputs (i.e., creating a `Post` should require a `PostCreate` and return a `PostRead` model, not reuse the same model).
75+
* Parameters in Pydantic models for user input should use the Field function with validation and descriptions.
76+
{%- endif %}
77+
78+
{%- if cookiecutter.include_sqlalchemy == "y" %}
79+
80+
### SQLAlchemy
81+
82+
* Always use async SQLAlchemy APIs with SQLAlchemy 2.0 syntax.
83+
* Represent database tables with the declarative class system.
84+
* Use Alembic to define migrations.
85+
* Migrations should be compatible with both SQLite and PostgreSQL.
86+
* When creating queries, do not use implicit `and`: instead use the `and_` function (instead of `where(Model.parameter_a == A, Model.parameter_b == B)` do `where(and_(Model.parameter_a == A, Model.parameter_b == B))`).
87+
{%- endif %}
88+
89+
{%- if cookiecutter.include_cli == "y" %}
90+
91+
### Typer
92+
93+
* Any CLI command or script that should be accessible to users should be exposed via the Typer library.
94+
* The main CLI entrypoint should be `PACKAGE_NAME/cli.py`.
95+
{%- endif %}
96+
97+
### Testing
98+
99+
* Do not wrap test functions in classes unless there is a specific technical reason: instead prefer single functions.
100+
* All fixtures should be defined or imported in `conftest.py` so they are available to all tests.
101+
* Do not use mocks to replace simple dataclasses or Pydantic models unless absolutely necessary: instead create an instance of the appropriate class with desired parameters.
102+
* Use the FastAPI Test Client (preferably with a fixture) rather than calling FastAPI router classes directly.
103+
* Use a test database fixture with memory-backed SQLite for tests requiring a database. Including a dependency override for this test database as part of the FastAPI App fixture is extremely useful.
104+
* When adding new code, you should also add appropriate tests to cover that new code.
105+
* The test suite file structure should mirror the main code file structure.
106+
107+
### Files
108+
109+
* Filenames should always be lowercase for better compatibility with case-insensitive filesystems.
110+
* This includes documentation files, except standard files (like `README.md`, `LICENSE`, etc.).
111+
* Developer documentation should live in `docs/dev`.
112+
* New developer documents should be added to the table of contents in `docs/dev/README.md`.
113+
* Files only meant for building containers should live in the `docker/` folder.
114+
* Database models should live in `PACKAGE_NAME/models/`.
115+
* The primary settings file should live in `PACKAGE_NAME/conf/settings.py`.
116+
117+
### Developer Environments
118+
119+
* Common developer tasks should be defined in the `makefile` to easy reuse.
120+
* Developers should always be able to start a fully functional developer instance with `docker compose up`.
121+
* Developer environments should be initialized with fake data for easy use.
122+
* Developer settings should live in the `.env` file, which should be in `.gitignore`.
123+
* A `.env.example` file should exist as a template for new developers to create their `.env` file and learn what variables to set.
124+
* Python projects should always use virtual environments at `.venv` in the project root. This should be activated before running tests.

0 commit comments

Comments
 (0)