{"slug": "agents-md-best-practices", "title": "Agents.md best practices", "summary": "AGENTS.md has become the de facto open standard for guiding AI coding assistants, with adoption surpassing 20,000 repositories and formalization in August 2025 through collaboration between OpenAI, Google, Cursor, Factory, and Sourcegraph. The plain-Markdown, schema-free file acts as a \"README for machines,\" giving agents exact environment setup, build and test commands, and code conventions, and it is now natively supported by GitHub Copilot, OpenAI Codex, Cursor, Google's Jules and Gemini, and others. OpenAI's main repository reportedly uses 88 AGENTS.md files across subcomponents, with the nearest file in the directory tree taking precedence.", "body_md": "AGENTS.md has emerged as the de facto open standard for guiding AI coding assistants, now adopted by **over 20,000 repositories** and formalized in August 2025 through collaboration between OpenAI, Google, Cursor, Factory, and Sourcegraph. This file acts as a \"README for machines\"—providing structured, technical context that helps AI assistants write better code from the start. For Python + AWS + Terraform projects, a well-crafted AGENTS.md dramatically reduces friction, ensuring generated code follows your conventions, uses the right tools, and adheres to security requirements.\n\nAGENTS.md is a dedicated Markdown file that **complements, not replaces, README.md**. While README targets human developers with project overviews and quick-start guides, AGENTS.md contains detailed technical instructions specifically for AI coding agents. Think of it as onboarding documentation for an AI team member: exact commands to run, code patterns to follow, testing strategies, deployment workflows, and project-specific gotchas.\n\nThe standard provides immediate benefits. AI assistants understand project requirements without a discovery phase, generated code adheres to team standards from the start, and code review cycles shrink. Most importantly, it works across the entire ecosystem—OpenAI Codex, GitHub Copilot, Cursor, Claude Code, Aider, and more—eliminating the need for multiple tool-specific configuration files.\n\n**Key adoption milestone**: GitHub Copilot added native AGENTS.md support in August 2025, joining OpenAI Codex, Cursor, Google's Jules and Gemini, Factory, Amp, Windsurf, Zed, and RooCode in supporting the standard. Android Studio's Gemini integration includes a context drawer specifically for managing AGENTS.md files.\n\nThe standard intentionally remains **simple and schema-free**—just plain Markdown with no required structure. This flexibility drove adoption, but effective implementations follow consistent patterns.\n\nUse **AGENTS.md** (plural) as the primary filename. Place it at the repository root alongside README.md. For monorepos or complex projects, place additional AGENTS.md files in subdirectories—the nearest file in the directory tree takes precedence, creating a hierarchical configuration system. OpenAI's main repository uses this pattern with **88 AGENTS.md files** across subcomponents.\n\nFor backward compatibility with legacy tools, create symlinks:\n\n```\nln -s AGENTS.md CLAUDE.md\nln -s AGENTS.md .github/copilot-instructions.md\nln -s AGENTS.md .cursorrules\n```\n\nResearch across successful implementations reveals these core sections:\n\n**Development environment setup comes first**. List exact commands for dependency installation, environment configuration, package manager usage, and tool version requirements. Be concrete:\n\n```\n## Environment Setup\n- Python 3.12+\n- Install UV: `curl -LsSf https://astral.sh/uv/install.sh | sh`\n- Create environment: `uv venv && source .venv/bin/activate`\n- Install dependencies: `uv sync`\n- Configure AWS: `aws configure` (requires credentials)\n```\n\n**Build and test commands second**. Provide file-scoped commands preferentially—agents should be able to check single files without running full builds. This dramatically improves iteration speed:\n\n```\n## Commands\n\n### File-scoped (preferred - fast feedback)\nuv run pytest tests/test_handlers.py\nuv run ruff check src/handlers.py\nuv run mypy src/handlers.py\n\n### Full suite (only when explicitly requested)\nuv run pytest --cov=src\nterraform fmt -recursive\n```\n\n**Code style and conventions third**. Be explicit about formatting, naming patterns, architectural decisions, library preferences, and version-specific requirements:\n\n```\n## Code Style\n- Python: Follow PEP 8, use type hints (mypy strict mode)\n- Formatting: Ruff (line length 88)\n- FastAPI: Async patterns for all I/O, Mangum for Lambda integration\n- PynamoDB: Always define table_name and region in Meta class\n- Terraform: snake_case naming, tag all resources (environment, project, managed_by)\n- Never use `@ts-ignore` or hardcode credentials\n```\n\n**Testing instructions and requirements**. Document test frameworks, locations, coverage expectations, and how to run different test types:\n\n```\n## Testing\n- Framework: pytest with moto for AWS service mocking\n- Unit tests: `uv run pytest tests/unit/`\n- Integration: `uv run pytest tests/integration/` (requires Docker)\n- Coverage requirement: 80%+ for new code\n- Mocking pattern: Use `@mock_dynamodb` decorator for DynamoDB tests\n```\n\n**Project structure and key files**. Help agents navigate your codebase without exploring repeatedly:\n\n```\n## Project Structure\n- `src/handlers/` - Lambda function handlers (thin, delegate to services)\n- `src/models/` - PynamoDB models (DynamoDB) and Pydantic models (API validation)\n- `src/services/` - Business logic (keep handlers thin)\n- `infrastructure/` - Terraform configs (modules pattern, workspaces for environments)\n- Key file: `src/api/client.ts` - Use this typed client, not raw fetch calls\n```\n\n**Safety and permission boundaries**. Define what agents can do autonomously versus what requires approval:\n\n```\n## Permissions\n\n### Allowed without prompting\n- Read files, list directories\n- Single file linting, type checking, formatting\n- Unit tests on specific files\n\n### Require approval first\n- Package installations (`uv add`, `npm install`)\n- Git operations (`git push`, `git commit`)\n- File deletion\n- Running full build or E2E test suites\n- Terraform apply/destroy operations\n```\n\n**Pull request and commit guidelines**. Ensure generated code follows team workflows:\n\n```\n## PR Requirements\n- Title format: [component] Brief description\n- Always run `uv run pytest && uv run ruff check .` before committing\n- Keep diffs small and focused\n- Tests required for new features\n- All CI checks must pass\n```\n\nKeep AGENTS.md **under 150 lines** when possible. Agents load files into context windows, and excessive length wastes tokens while burying important information. For large projects, use nested AGENTS.md files in subdirectories or leverage file imports where supported:\n\n```\n# Root AGENTS.md\nYou are an experienced Python developer.\n\n@./docs/python-guidelines.md\n\n## Testing\n@./docs/testing-patterns.md\n```\n\nAndroid Studio's Gemini and some other tools support this `@./path/to/file.md` syntax for modular documentation.\n\nUnderstanding how different tools consume AGENTS.md helps you write more effective instructions.\n\n**OpenAI Codex** automatically searches for AGENTS.md files whose scope includes modified files, prioritizing deeper nested instructions in a cascading configuration pattern. Contents are included in the system prompt, and Codex's `/init` command can generate an initial AGENTS.md by analyzing project structure.\n\n**GitHub Copilot** processes AGENTS.md server-side as of August 2025. It automatically detects and appends contents to system prompts for Copilot Chat, Coding Agent, and Code Review features. Path-specific instructions use YAML frontmatter with glob patterns:\n\n```\n---\napplyTo: \"src/handlers/**/*.py\"\n---\nLambda handler instructions here\n```\n\n**Cursor IDE** supports both simple AGENTS.md (automatic detection at project root) and an advanced `.cursor/rules/` system with `.mdc` files that include metadata for conditional loading:\n\n```\n---\ndescription: \"DynamoDB model standards\"\nglobs: \"src/models/**/*.py\"\nalwaysApply: false\n---\nPynamoDB patterns and conventions\n```\n\nCursor offers four rule types: Always (always included), Auto Attached (included when matching files are referenced), Agent Requested (AI decides based on description), and Manual (only when explicitly mentioned).\n\n**Claude Code** primarily uses `CLAUDE.md` but reads AGENTS.md via symlinks. Its `/init` command generates customized project instructions including code hooks for pre/post-edit validation. Claude Code supports hierarchical files where the most nested takes precedence, and integrates with a Skills system—organized folders with `SKILL.md` files for specialized capabilities.\n\n**Other tools**: Aider requires configuration via `.aider.conf.yml` (`read: AGENTS.md`), Gemini CLI via `.gemini/settings.json` (`{\"contextFileName\": \"AGENTS.md\"}`), and most modern tools either support AGENTS.md natively or through simple configuration.\n\nDifferent tools have varying token limits: OpenAI Codex offers 128k-192k tokens, Claude Opus 4 provides 200k, GitHub Copilot varies by model (GPT-4o ~128k, Claude available), and Gemini reaches 1 million tokens (2 million for Pro).\n\nTools employ several context prioritization strategies. Proximity-based approaches favor closer or nested files. Relevance-based systems let the AI decide what's important from file descriptions. Explicit @-mentions force inclusion. Automatic trimming removes older context as limits approach. Hierarchical merging combines parent and child rules.\n\nMost tools combine multiple search approaches. **Text-based search** (grep, ripgrep) provides fast exact matches. **Semantic search** with vector embeddings finds conceptually related code. **AST-based search** parses code structure for accurate, language-aware results. Effective AGENTS.md files account for these by providing clear, searchable keywords and explicit file paths.\n\nThe most effective AGENTS.md files lead with commands rather than explanations. Setup commands first, testing second, deployment third, debugging last. From OpenAI's sample:\n\n```\n## Dev environment tips\n- Use `pnpm dlx turbo run where <project_name>` to jump to a package\n- Run `pnpm install --filter <project_name>` to add the package\n- Check the name field inside package.json to confirm the right name\n\n## Testing instructions\n- Find the CI plan in .github/workflows folder\n- Run `pnpm turbo run test --filter <project_name>`\n- From package root: `pnpm test`\n- Focus on one test: `pnpm vitest run -t \"<test name>\"`\n\n## PR instructions\n- Title format: [<project_name>] <Title>\n- Always run `pnpm lint` and `pnpm test` before committing\n```\n\nStrong implementations explicitly point to files demonstrating best patterns and warn against legacy code:\n\n```\n## Code Examples\n\n### ✅ Good Patterns\n- PynamoDB models: `src/models/user.py` (hash/range keys, batch operations)\n- FastAPI handlers: `src/handlers/api.py` (async, Mangum integration)\n- Terraform modules: `infrastructure/modules/lambda/` (reusable, well-documented)\n\n### ❌ Avoid These\n- `src/legacy/old_handler.py` - Synchronous patterns (deprecated)\n- `infrastructure/monolith.tf` - Pre-modules structure (being migrated)\n- Hardcoded colors, credentials, or region names anywhere\n```\n\nLarge codebases use nested AGENTS.md files to provide context-specific guidance:\n\n```\nproject/\n├── AGENTS.md                    # Organization-wide standards\n├── backend/\n│   └── AGENTS.md               # Python/FastAPI specific\n├── infrastructure/\n│   └── AGENTS.md               # Terraform specific\n└── frontend/\n    └── AGENTS.md               # React specific\n```\n\nEach file focuses on its domain. The root covers general practices, while subdirectory files provide technology-specific details.\n\nFor serverless Python applications with AWS and infrastructure-as-code, AGENTS.md requires special considerations.\n\nBe explicit about versions, package managers, and tools:\n\n```\n# Technology Stack\n- **Runtime**: Python 3.12 (AWS Lambda)\n- **Package Manager**: UV (replaces pip/poetry)\n- **API Framework**: FastAPI with Mangum adapter\n- **AWS Services**: Lambda, DynamoDB, S3, API Gateway\n- **IaC**: Terraform 1.5+ with S3 backend + DynamoDB locking\n- **Database ORM**: PynamoDB for DynamoDB\n- **Validation**: Pydantic v2 models\n- **Testing**: pytest with moto (AWS service mocking)\n```\n\nUV is 10-100x faster than pip and replaces multiple tools. Document its complete workflow:\n\n```\n## UV Package Manager\n\n### Initial Setup\ncurl -LsSf https://astral.sh/uv/install.sh | sh\nuv venv\nsource .venv/bin/activate  # Linux/Mac\n\n### Dependency Management\nuv sync                     # Install from lock file\nuv add boto3                # Add runtime dependency\nuv add --group dev pytest   # Add dev dependency\nuv add \"fastapi>=0.110,<1\"  # Add with version constraint\nuv lock                     # Update lock file\nuv run <command>            # Run command in venv\n\n### Important\n- Commit `uv.lock` for reproducibility\n- Use `uv sync` for consistent environments\n- Always specify version constraints for AWS SDKs\n```\n\nPynamoDB requires specific configuration. Document common patterns:\n\n``` python\n## PynamoDB Models\n\n### Basic Structure\nfrom pynamodb.models import Model\nfrom pynamodb.attributes import UnicodeAttribute, NumberAttribute\n\nclass UserModel(Model):\n    class Meta:\n        table_name = 'users'\n        region = 'us-east-1'  # CRITICAL: Must match table region\n    \n    user_id = UnicodeAttribute(hash_key=True)\n    email = UnicodeAttribute()\n    created_at = NumberAttribute()\n    metadata = UnicodeAttribute(null=True)  # Use null=True for optional\n\n### Best Practices\n- Always define table_name and region in Meta class\n- Use batch_write() and batch_get() for multiple items (efficiency)\n- Mark optional fields with null=True (saves storage costs)\n- Use conditional operations for concurrency control\n- Test with moto: `@mock_dynamodb` decorator\n```\n\nPydantic serves dual purposes—API request/response validation and data modeling:\n\n``` python\n## Pydantic Models\n\nfrom pydantic import BaseModel, Field, EmailStr\n\nclass UserRequest(BaseModel):\n    email: EmailStr\n    name: str = Field(min_length=1, max_length=100)\n    age: int | None = Field(None, gt=0, lt=150)\n    \n    class Config:\n        json_schema_extra = {\n            \"example\": {\n                \"email\": \"user@example.com\",\n                \"name\": \"John Doe\",\n                \"age\": 30\n            }\n        }\n\n### Usage\n- Request/response validation in FastAPI\n- Field() for constraints (min_length, gt, lt, regex)\n- Type unions (|) for optional fields\n- Nested models for complex structures\n- Examples auto-generate OpenAPI documentation\n```\n\nDocument the Mangum adapter pattern for FastAPI in Lambda:\n\n``` python\n## Lambda Handlers\n\nfrom fastapi import FastAPI\nfrom mangum import Mangum\n\napp = FastAPI()\n\n@app.get(\"/users/{user_id}\")\nasync def get_user(user_id: str):\n    # Separate handler from business logic\n    return UserService().get_user(user_id)\n\n# Lambda handler\nhandler = Mangum(app)\n\n### Best Practices\n- Keep handlers thin, move logic to service classes\n- Initialize AWS clients outside handler for reuse (Lambda container reuse)\n- Use async patterns for all I/O operations\n- Handle cold starts: provisioned concurrency or SnapStart for critical endpoints\n- Environment variables for configuration (never hardcode)\n```\n\nInfrastructure-as-code requires comprehensive command documentation:\n\n```\n## Terraform Commands\n\n### Initialization and Validation\ncd infrastructure\nterraform init\nterraform validate\nterraform fmt -recursive  # Always run before committing\n\n### Planning and Applying\nterraform plan -var-file=environments/dev.tfvars -out=tfplan\nterraform apply tfplan\n\n### Workspace Management (Multi-Environment)\nterraform workspace list\nterraform workspace select dev\nterraform workspace new staging\n\n### State Management\nterraform state list\nterraform state show aws_lambda_function.api\nterraform show\n\n### Destruction\nterraform destroy -var-file=environments/dev.tfvars\n\n## Terraform Best Practices\n- Store state in S3 with DynamoDB locking\n- Use workspaces for environments (dev/staging/prod)\n- Tag all resources: environment, project, managed_by, cost_center\n- Use modules for reusable components\n- Document all variables with description and type\n- Enable versioning on S3 state bucket\n- Always run `terraform fmt` before committing\n- Use `terraform plan` before every apply\n```\n\nAWS service mocking is critical for unit tests:\n\n``` python\n## Testing with Moto\n\n### Basic Pattern\nimport pytest\nfrom moto import mock_dynamodb\n\n@mock_dynamodb\ndef test_user_creation():\n    # Moto intercepts boto3 calls\n    UserModel.create_table(read_capacity_units=1, write_capacity_units=1)\n    user = UserModel(user_id='123', email='test@example.com')\n    user.save()\n    \n    # Retrieve and assert\n    retrieved = UserModel.get('123')\n    assert retrieved.email == 'test@example.com'\n\n### Test Structure\ntests/\n├── unit/              # Mocked AWS services\n│   ├── test_models.py\n│   └── test_handlers.py\n├── integration/       # Real AWS (LocalStack or deployed)\n│   └── test_api.py\n└── conftest.py        # Shared fixtures\n\n### Commands\nuv run pytest tests/unit/              # Fast, mocked\nuv run pytest tests/integration/       # Slower, requires setup\nuv run pytest --cov=src --cov-report=html\n```\n\nDocument both local and CI/CD deployment:\n\n```\n## Deployment\n\n### Local Development\nuv run uvicorn src.main:app --reload  # FastAPI locally\nsam local invoke MyFunction -e events/test.json  # Test Lambda locally\nsam local start-api  # Local API Gateway\n\n### Infrastructure Deployment\ncd infrastructure\nterraform workspace select prod\nterraform plan -var-file=environments/prod.tfvars\nterraform apply -var-file=environments/prod.tfvars\n\n### CI/CD Pipeline (GitHub Actions)\n- Workflow: `.github/workflows/deploy.yml`\n- Triggered on: merge to main\n- Stages: Test → Security Scan → Terraform Plan → Manual Approval → Terraform Apply\n- Deployment gates:\n  - All tests pass (pytest, mypy, ruff)\n  - Security scan clean (Snyk, Bandit)\n  - Code coverage ≥80%\n  - Manual approval for production\n\n### Rollback\nterraform workspace select prod\nterraform apply -var-file=environments/prod.tfvars -target=aws_lambda_function.api -var=\"lambda_version=previous\"\n```\n\nFor projects combining service code and infrastructure:\n\n**Option 1: Single comprehensive AGENTS.md**\n\n```\n# Project: Serverless API\n\n[Overview section]\n[Python/FastAPI section]\n[PynamoDB section]\n[Testing section]\n[Terraform section]\n[Deployment section]\n```\n\n**Option 2: Nested AGENTS.md files (preferred for complex projects)**\n\n```\nproject/\n├── AGENTS.md                    # Overview + integration points\n├── src/\n│   └── AGENTS.md               # Python, FastAPI, PynamoDB, testing\n├── infrastructure/\n│   └── AGENTS.md               # Terraform, state management, modules\n└── tests/\n    └── AGENTS.md               # Testing strategies, mocking patterns\n```\n\nStart with a single file. Split into subdirectories when any section exceeds 200 lines.\n\nSecurity is paramount in AGENTS.md. One leaked credential can compromise entire systems.\n\n**Absolutely forbidden**:\n\n- API keys, tokens, passwords, or any credentials\n- Database connection strings with passwords\n- AWS access keys or secret keys\n- Private encryption keys or certificates\n- OAuth secrets or JWT signing keys\n- Production IP addresses or internal URLs\n- Customer data or personally identifiable information\n- Proprietary algorithms or trade secrets\n- Security vulnerability details\n- Detailed firewall or security group configurations\n\nResearch shows GitHub identified **39 million leaked secrets** in 2024, with projects using AI assistants showing a **40% increase in secrets exposure**. AI assistants may also inadvertently include leaked secrets in generated code.\n\nDocument **where** secrets live and **how** to access them, never the secrets themselves:\n\n```\n## Secrets Management\n\n### Secret Storage Locations\n- **Production**: AWS Secrets Manager (`prod/*` namespace)\n- **Staging**: AWS Secrets Manager (`staging/*` namespace)\n- **Development**: Local `.env` file (gitignored, copy from `.env.example`)\n- **CI/CD**: GitHub Actions Secrets\n\n### Accessing Secrets in Code\n# Python example\nimport boto3\n\nsecrets_client = boto3.client('secretsmanager', region_name='us-east-1')\nsecret = secrets_client.get_secret_value(SecretId='prod/api-key')\n\n# NEVER: api_key = \"sk_live_abc123...\"\n\n### Required Environment Variables (Structure Only)\n- `DATABASE_URL`: PostgreSQL connection (format: postgresql://user:pass@host:port/db)\n- `API_KEY`: External API auth (retrieve from secrets manager)\n- `JWT_SECRET`: Token signing (minimum 32 characters, from secrets manager)\n\n### Security Rules\n- NEVER commit `.env` files\n- NEVER hardcode credentials\n- NEVER log secret values\n- NEVER pass secrets as command-line arguments\n- ALWAYS use secrets manager for production\n- ALWAYS run secret scanning before commits: `uv run bandit -r src/`\n```\n\nWhile commonly used, environment variables have significant limitations:\n\n- Accessible to all spawned child processes\n- Readable via `/proc` or`ps` commands by any process with same user\n- Often inadvertently logged in error messages or crash reports\n- Inherited by every subprocess automatically\n- No built-in auditing\n\nThe CNCF Cloud Native Security Whitepaper states: \"Secrets should be injected at runtime within workloads through non-persistent mechanisms that are immune to leaks via logs, audit, or system dumps (i.e., in-memory shared volumes instead of environment variables).\"\n\n**Better alternatives**: AWS Secrets Manager, HashiCorp Vault, Azure Key Vault, Kubernetes secrets as tmpfs volumes, or encrypted secrets files with proper permissions.\n\nDocument required security tooling:\n\n```\n## Security Requirements\n\n### Pre-Commit Checks\n- Secret scanning: `uv run detect-secrets scan --all-files`\n- Dependency vulnerabilities: `uv run pip-audit`\n- Code security: `uv run bandit -r src/`\n- Terraform security: `tfsec infrastructure/`\n\n### CI/CD Security Gates\n- GitHub push protection (blocks commits with secrets)\n- Snyk scanning (dependency vulnerabilities)\n- Semgrep (code patterns and security rules)\n- All scans must pass before merge allowed\n\n### AWS Security\n- Use IAM roles for Lambda (principle of least privilege)\n- Enable CloudTrail for audit logging\n- Encrypt DynamoDB tables at rest\n- Use VPC for sensitive Lambda functions\n- Enable S3 bucket encryption and versioning\n- Rotate IAM access keys quarterly\n```\n\nEffective AGENTS.md files make CI/CD transparent to AI assistants.\n\n```\n## CI/CD Pipeline\n\n### GitHub Actions Workflows\n- **CI**: `.github/workflows/ci.yml` (runs on all PRs)\n  - Stages: Lint → Type Check → Unit Tests → Security Scan → Build\n  - Must pass before merge allowed\n- **Deploy**: `.github/workflows/deploy.yml` (runs on main branch)\n  - Stages: Integration Tests → Terraform Plan → Manual Approval → Terraform Apply\n  - Separate jobs for staging and production\n\n### Local CI Simulation\n# Run all CI checks locally before pushing\nuv run ruff check src/\nuv run mypy src/\nuv run pytest tests/unit/\nuv run bandit -r src/\nterraform fmt -check -recursive\n\n### Deployment Environments\n- **Development**: Auto-deploy on push to `develop` branch\n- **Staging**: Auto-deploy on merge to `main` branch\n- **Production**: Manual approval required after staging validation\n```\n\nComprehensive testing documentation prevents common issues:\n\n```\n## Testing Instructions\n\n### Prerequisites\n- Python 3.12+\n- Docker (for integration tests using LocalStack)\n- AWS CLI configured (for integration tests against real AWS)\n- PostgreSQL 15+ running on port 5432 (for API integration tests)\n\n### Test Database Setup\ndocker-compose up -d postgres\nuv run alembic upgrade head\nuv run python scripts/seed_test_data.py\n\n### Running Tests\n\n#### File-Scoped (Preferred - Fast Feedback)\nuv run pytest tests/unit/test_handlers.py        # Single file\nuv run pytest tests/unit/test_handlers.py::test_create_user  # Single test\nuv run pytest -k \"test_user\"                     # Pattern match\n\n#### Full Test Suite\nuv run pytest tests/unit/                        # All unit tests (fast)\nuv run pytest tests/integration/                 # Integration tests (slower)\nuv run pytest                                    # Everything\n\n#### With Coverage\nuv run pytest --cov=src --cov-report=html --cov-report=term\nopen htmlcov/index.html\n\n### Test Requirements\n- All new features require unit tests\n- API endpoints require integration tests\n- Coverage must be ≥80% for new code\n- Use moto for mocking AWS services in unit tests\n- Use LocalStack or real AWS for integration tests\n```\n\nDefine what must be true before deployment:\n\n```\n## Deployment Requirements\n\n### Merge Requirements\n- All CI checks pass (lint, type check, tests, security scan)\n- Code coverage ≥80%\n- No high or critical severity vulnerabilities\n- At least one approved code review\n- Branch protection rules enforced\n\n### Production Deployment Gates\n1. Successful staging deployment and smoke tests\n2. Manual approval from team lead\n3. Deployment window (weekdays 10am-4pm EST, no Fridays)\n4. Rollback plan documented in deployment PR\n\n### Post-Deployment Validation\n- Health check endpoint returns 200: `curl https://api.example.com/health`\n- CloudWatch logs show no errors: `aws logs tail /aws/lambda/api --follow`\n- Key metrics within normal ranges (check Datadog dashboard)\n- Smoke tests pass: `pytest tests/smoke/`\n```\n\nLearning from real-world failures prevents repeated mistakes.\n\n**❌ Wrong**:\n\n```\nDATABASE_URL=postgresql://admin:MyP@ssw0rd@prod-db.company.com/maindb\nAPI_KEY=sk_live_abc123xyz789\nAWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE\n```\n\n**✅ Correct**:\n\n```\n## Configuration\n- `DATABASE_URL`: From AWS Secrets Manager (` prod/database`)\n- `API_KEY`: From environment variables (set in Lambda config)\n- AWS credentials: Use IAM roles (never access keys in Lambda)\n```\n\nMassive 1000+ line files waste tokens and bury important information. Link to detailed documentation instead:\n\n**❌ Wrong**: Pasting entire API specifications, comprehensive architecture diagrams, complete tutorials.\n\n**✅ Correct**:\n\n```\n## Architecture\nServerless API: FastAPI → Lambda → API Gateway → DynamoDB\n\nFor detailed architecture: [docs/architecture.md](docs/architecture.md)\nFor API reference: [docs/api-reference.md](docs/api-reference.md)\n```\n\n**❌ Wrong**:\n\n```\n- Run the tests\n- Build it properly\n- Deploy carefully\n```\n\n**✅ Correct**:\n\n```\n## Testing\n- Unit tests: `uv run pytest tests/unit/` (fast, mocked AWS)\n- Integration: `uv run pytest tests/integration/` (requires Docker)\n- All tests: `uv run pytest` (runs both suites)\n- CI must pass before merge\n\n## Deployment\n- Staging: Auto-deploys on merge to main\n- Production: Run `terraform apply` after manual approval in GitHub Actions\n```\n\nAI agents running complete test suites for every small change wastes time:\n\n**❌ Wrong**:\n\n```\n## Testing\nAlways run: `npm run build && npm test && npm run e2e`\n```\n\n**✅ Correct**:\n\n```\n## Testing\n\n### File-Scoped (Preferred - Fast)\nuv run pytest tests/test_handlers.py\nuv run ruff check src/handlers.py\nuv run mypy src/handlers.py\n\n### Full Suite (Only When Explicitly Requested)\nuv run pytest --cov=src\nuv run ruff check .\nterraform fmt -recursive\n```\n\n**❌ Wrong**: No guidance on what AI can do autonomously versus what requires approval.\n\n**✅ Correct**:\n\n```\n## Permissions\n\n### Allowed Without Prompting\n- Read any source file\n- Run linters, formatters, type checkers on single files\n- Run unit tests on specific test files\n\n### Require Approval First\n- Installing packages (`uv add`, `npm install`)\n- Git operations (`git push`, `git commit`)\n- Deleting files or directories\n- Running full build or E2E tests\n- Terraform apply or destroy\n- Modifying CI/CD configuration\n```\n\nAI agents may copy legacy or anti-pattern code without explicit guidance:\n\n**✅ Correct**:\n\n```\n## Code Examples\n\n### ✅ Good Patterns\n- PynamoDB model: `src/models/user.py` (proper Meta class, batch operations)\n- FastAPI endpoint: `src/handlers/projects.py` (async, thin handlers)\n- Terraform module: `infrastructure/modules/lambda/` (reusable, documented)\n\n### ❌ Avoid These\n- `src/legacy/sync_handler.py` - Synchronous patterns (deprecated)\n- `src/utils/raw_boto3.py` - Direct boto3 without error handling\n- Hardcoded credentials, regions, or table names anywhere\n```\n\nAGENTS.md must evolve with the codebase:\n\n- Review in pull requests when processes change\n- Treat as code, not static documentation\n- Audit quarterly for accuracy\n- Update immediately when commands or structure change\n\nSingle AGENTS.md for large monorepos creates confusion:\n\n**✅ Correct approach**:\n\n```\nmonorepo/\n├── AGENTS.md                    # Org-wide standards, general patterns\n├── python-api/\n│   └── AGENTS.md               # Python/FastAPI/PynamoDB specific\n├── infrastructure/\n│   └── AGENTS.md               # Terraform/AWS specific\n└── typescript-frontend/\n    └── AGENTS.md               # React/TypeScript specific\n```\n\nNearest file takes precedence, allowing context-specific guidance.\n\n```\n# Project Name\n\nBrief description of serverless application, purpose, and architecture.\n\n# Technology Stack\n- **Runtime**: Python 3.12 (AWS Lambda)\n- **Package Manager**: UV\n- **API Framework**: FastAPI with Mangum\n- **AWS Services**: Lambda, DynamoDB (PynamoDB), S3, API Gateway\n- **IaC**: Terraform 1.5+ (S3 backend, DynamoDB locking)\n- **Testing**: pytest with moto\n- **Validation**: Pydantic v2\n\n# Architecture\n- `src/handlers/` - Lambda handlers (thin, async)\n- `src/models/` - PynamoDB (DynamoDB) and Pydantic (API) models\n- `src/services/` - Business logic\n- `infrastructure/` - Terraform (modules pattern, workspaces)\n- `tests/` - Unit (moto) and integration tests\n\n# Environment Setup\n\n## Prerequisites\n- Python 3.12+\n- UV: `curl -LsSf https://astral.sh/uv/install.sh | sh`\n- AWS CLI configured: `aws configure`\n- Terraform 1.5+: `brew install terraform`\n- Docker (for integration tests)\n\n## Initial Setup\nuv venv && source .venv/bin/activate\nuv sync\ncp .env.example .env  # Populate from team vault\n\n## AWS Configuration\naws configure  # Set credentials and region\nexport AWS_DEFAULT_REGION=us-east-1\n\n# Commands\n\n## File-Scoped (Preferred - Fast)\nuv run pytest tests/unit/test_handlers.py\nuv run ruff check src/handlers.py\nuv run mypy src/handlers.py\n\n## Full Suite (Only When Requested)\nuv run pytest --cov=src\nuv run ruff check .\nterraform fmt -recursive\n\n## Terraform\ncd infrastructure\nterraform init\nterraform workspace select dev\nterraform plan -var-file=environments/dev.tfvars\nterraform apply -var-file=environments/dev.tfvars\n\n# Code Patterns\n\n## PynamoDB Models\nfrom pynamodb.models import Model\nfrom pynamodb.attributes import UnicodeAttribute\n\nclass UserModel(Model):\n    class Meta:\n        table_name = 'users'\n        region = 'us-east-1'  # Must match table region\n    \n    user_id = UnicodeAttribute(hash_key=True)\n    email = UnicodeAttribute()\n\n- Always define table_name and region in Meta\n- Use batch_write() for multiple items\n- Mark optional fields: null=True\n\n## Pydantic Models\nfrom pydantic import BaseModel, Field\n\nclass UserRequest(BaseModel):\n    email: str = Field(..., pattern=r'^[\\w\\.-]+@[\\w\\.-]+\\.\\w+$')\n    age: int | None = Field(None, gt=0, lt=150)\n\n- Use for API validation\n- Field() for constraints\n- Type unions (|) for optional\n\n## FastAPI + Lambda\nfrom fastapi import FastAPI\nfrom mangum import Mangum\n\napp = FastAPI()\n\n@app.get(\"/users/{user_id}\")\nasync def get_user(user_id: str):\n    return UserService().get_user(user_id)\n\nhandler = Mangum(app)\n\n- Keep handlers thin\n- Async for all I/O\n- Initialize AWS clients outside handler\n\n# Testing\n\n## Structure\ntests/\n├── unit/              # Mocked AWS (moto)\n├── integration/       # Real AWS or LocalStack\n└── conftest.py        # Shared fixtures\n\n## Running Tests\nuv run pytest tests/unit/              # Fast, mocked\nuv run pytest tests/integration/       # Requires Docker/AWS\nuv run pytest --cov=src --cov-report=html\n\n## Requirements\n- 80%+ coverage for new code\n- Unit tests for all business logic\n- Integration tests for API endpoints\n- Use `@mock_dynamodb` for DynamoDB mocking\n\n# Terraform\n\n## Commands\nterraform init\nterraform validate\nterraform fmt -recursive  # Before committing\nterraform plan -var-file=environments/dev.tfvars -out=tfplan\nterraform apply tfplan\n\n## Best Practices\n- Store state in S3 with DynamoDB locking\n- Use workspaces for environments\n- Tag all resources: environment, project, managed_by\n- Always run fmt before committing\n- Document all variables\n\n# Security\n\n## Secrets Management\n- Production: AWS Secrets Manager (`prod/*`)\n- Development: `.env` (gitignored)\n- CI/CD: GitHub Actions Secrets\n- Never commit credentials or `.env` files\n\n## Security Scanning\nuv run bandit -r src/              # Code security\nuv run pip-audit                   # Dependency vulnerabilities\ntfsec infrastructure/              # Terraform security\n\n## AWS Security\n- Use IAM roles (principle of least privilege)\n- Enable CloudTrail for audit logging\n- Encrypt DynamoDB at rest\n- VPC for sensitive functions\n\n# Deployment\n\n## Local Development\nuv run uvicorn src.main:app --reload\nsam local invoke MyFunction -e events/test.json\n\n## Infrastructure\ncd infrastructure\nterraform workspace select prod\nterraform plan -var-file=environments/prod.tfvars\nterraform apply -var-file=environments/prod.tfvars\n\n## CI/CD\n- Workflow: `.github/workflows/deploy.yml`\n- Staging: Auto-deploy on merge to main\n- Production: Manual approval required\n- Gates: Tests pass, security scan clean, code review approved\n\n# Code Style\n- Python: PEP 8, type hints (mypy strict)\n- Formatting: Ruff (line length 88)\n- Imports: Group stdlib, third-party, local\n- Docstrings: Google style\n- Never hardcode credentials, regions, or table names\n\n# Good Examples\n- PynamoDB: `src/models/user.py`\n- FastAPI: `src/handlers/projects.py`\n- Terraform: `infrastructure/modules/lambda/`\n\n# Avoid\n- `src/legacy/sync_handler.py` - Synchronous patterns\n- Hardcoded anything\n- Direct boto3 without error handling\n\n# Permissions\n\n## Allowed Without Prompting\n- Read files\n- Lint/test single files\n- Type checking\n\n## Require Approval\n- `uv add` (package installations)\n- `git push` (git operations)\n- File deletion\n- `terraform apply/destroy`\n- Full test suites\n\n# Troubleshooting\n\n## Lambda Timeout\n- Increase timeout in Terraform (max 15 minutes)\n- Enable provisioned concurrency for critical endpoints\n\n## PynamoDB Can't Find Table\n- Check region in Meta class matches table region\n- Verify table exists: `aws dynamodb list-tables`\n\n## Terraform State Lock\n- Force unlock: `terraform force-unlock <LOCK_ID>`\n\n# Additional Resources\n- UV: https://docs.astral.sh/uv/\n- PynamoDB: https://pynamodb.readthedocs.io/\n- FastAPI: https://fastapi.tiangolo.com/\n- Terraform AWS: https://registry.terraform.io/providers/hashicorp/aws/\n```\n\nFor smaller projects, start minimal and expand as needed:\n\n```\n# Project Name\n\nBrief description.\n\n# Setup\nuv venv && source .venv/bin/activate\nuv sync\n\n# Commands\nuv run pytest tests/\nuv run ruff check src/\n\n# Code Style\n- Python: PEP 8, type hints\n- Formatting: Ruff\n- Tests required for new features\n\n# Testing\nuv run pytest tests/unit/test_file.py  # Single file\nuv run pytest  # All tests\n\n# Security\n- Never commit .env files\n- Store secrets in environment variables\n- Run `uv run bandit -r src/` before committing\n```\n\nBegin with 20-30 lines covering the most critical information: setup commands, testing, and code style. Add sections based on what AI assistants repeatedly get wrong. The best AGENTS.md files evolve from real usage.\n\nEvery command should be copy-pasteable and work exactly as written. Avoid \"run the usual tests\" in favor of \"uv run pytest tests/unit/test_handlers.py\". Provide file paths, flags, and expected output where helpful.\n\nWhat would you tell a new teammate who needs to make their first code change? Setup, make a change, test it, submit it. That's your AGENTS.md outline.\n\nUpdate AGENTS.md in pull requests when processes change. Review during code reviews. Keep synchronized with README.md. Audit quarterly for accuracy. Outdated instructions are worse than no instructions.\n\nDefine clear permission boundaries. File-scoped operations (linting single files, running specific tests) can happen automatically. Risky operations (package installations, git pushes, infrastructure changes) require approval. This balance maintains productivity while preventing accidents.\n\nInclude guidance like \"When stuck, ask a clarifying question\" or \"If tests fail repeatedly, ask for human review.\" AI assistants should know when to ask for help.\n\nStart with a single AGENTS.md. When it exceeds 150-200 lines, split into subdirectories with nested files. Root file covers organization-wide standards, subdirectory files provide context-specific details. The nearest file takes precedence.\n\nReference existing documentation rather than copying it. \"For API details, see [docs/api.md]\" saves tokens and prevents drift between AGENTS.md and actual documentation.\n\nAsk an AI assistant to perform common tasks using only your AGENTS.md. Can it set up the environment? Run tests? Deploy code? Iterate based on where it gets stuck or makes mistakes.\n\nWhile AGENTS.md works across most modern AI coding tools, some advanced features vary. File imports (`@./file.md`) work in some tools but not others. Glob patterns in frontmatter work in GitHub Copilot and Cursor but not universally. Stick to standard Markdown for maximum compatibility.\n\nTreat AGENTS.md as potentially public. Never include actual secrets. Assume it could be used to train models. Reference secret storage systems, never secrets themselves. Run secret scanning before committing. Enable GitHub push protection.\n\nThe adoption of AGENTS.md represents a fundamental shift in how we document software projects. As AI assistants become standard development tools, having machine-readable, actionable guidance becomes as important as human-readable documentation. A well-crafted AGENTS.md file is an investment that pays dividends every time an AI assistant generates code that works correctly the first time, follows your conventions, and passes all checks without manual intervention.\n\nFor Python + AWS + Terraform projects specifically, the combination of UV package management documentation, PynamoDB patterns, Pydantic validation examples, FastAPI + Lambda integration guidance, comprehensive Terraform commands, and moto-based testing strategies creates a complete blueprint for AI-assisted serverless development. The result is faster development cycles, fewer code review iterations, and more consistent codebases—exactly what AGENTS.md was designed to deliver.", "url": "https://wpnews.pro/news/agents-md-best-practices", "canonical_source": "https://gist.github.com/wadaba4/254344aa5fd0e04a61df230f7aa1635e", "published_at": "2026-10-12 05:49:08+00:00", "updated_at": "2026-10-12 06:09:19.616238+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools", "agent-protocols"], "entities": ["OpenAI", "Google", "Cursor", "Factory", "Sourcegraph", "GitHub Copilot", "Claude Code"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/agents-md-best-practices", "markdown": "https://wpnews.pro/news/agents-md-best-practices.md", "text": "https://wpnews.pro/news/agents-md-best-practices.txt", "jsonld": "https://wpnews.pro/news/agents-md-best-practices.jsonld"}}