|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +## Commands |
| 4 | + |
| 5 | +- `pip install -e ".[dev]"` -- Install with dev dependencies |
| 6 | +- `pytest` -- Run all 140 tests |
| 7 | +- `pytest tests/test_run_command.py -v` -- Single test module |
| 8 | +- `ruff check src/pygate/` -- Lint |
| 9 | +- `ruff check src/pygate/ --fix` -- Lint with auto-fix |
| 10 | +- `pyright src/pygate/` -- Type check (basic mode) |
| 11 | +- `python -m build` -- Build wheel and sdist |
| 12 | +- `pygate run` -- Run all quality gates |
| 13 | +- `pygate repair --max-attempts 3` -- Auto-repair lint failures |
| 14 | +- `pygate summarize` -- Generate agent-readable brief |
| 15 | + |
| 16 | +## Testing |
| 17 | + |
| 18 | +- Framework: `pytest` (config in `pyproject.toml` under `[tool.pytest.ini_options]`) |
| 19 | +- Test location: `tests/`, one file per source module |
| 20 | +- Fixtures: `tests/conftest.py` + JSON fixtures in `tests/fixtures/` |
| 21 | +- All tests run offline — no subprocess execution, all gate outputs are mocked |
| 22 | +- Run single test: `pytest tests/test_gates_ruff.py::test_ruff_parse -v` |
| 23 | + |
| 24 | +## Project Structure |
| 25 | + |
| 26 | +``` |
| 27 | +src/pygate/ |
| 28 | + cli.py # Argument parsing, subcommand dispatch |
| 29 | + run_command.py # `pygate run` — orchestrates gate execution |
| 30 | + repair_command.py # `pygate repair` — bounded auto-fix loop (ruff --fix) |
| 31 | + summarize_command.py # `pygate summarize` — agent brief from JSON artifacts |
| 32 | + gates/ # Individual gate implementations |
| 33 | + ruff.py # Ruff lint gate (JSON output parsing) |
| 34 | + pyright.py # Pyright type-check gate |
| 35 | + pytest_gate.py # Pytest gate (--json-report parsing) |
| 36 | + models.py # Pydantic models (GateResult, Failure, Escalation, etc.) |
| 37 | + config.py # pygate.toml / pyproject.toml config loading |
| 38 | + constants.py # Exit codes, default paths |
| 39 | + exec.py # Subprocess execution wrapper |
| 40 | + env.py # Environment detection (CI, tool availability) |
| 41 | + fs.py # File operations (artifact writes) |
| 42 | + deterministic_fix.py # Safe ruff --fix wrapper with rollback |
| 43 | +schemas/ # JSON schemas for all artifact types |
| 44 | +demo/artifacts/ # Example output from each command |
| 45 | +``` |
| 46 | + |
| 47 | +## Code Style |
| 48 | + |
| 49 | +- Python 3.10+ required (`from __future__ import annotations` in all modules) |
| 50 | +- Pydantic v2 `BaseModel` for all structured data (not dataclasses) |
| 51 | +- `str(Enum)` for status values (`GateStatus.PASS`, `RunMode.CANARY`, etc.) |
| 52 | +- Ruff line length: 120, rules: `E, F, W, I, UP, B, SIM` |
| 53 | +- Pyright basic mode |
| 54 | +- Build system: hatchling |
| 55 | + |
| 56 | +Good: |
| 57 | +```python |
| 58 | +from pydantic import BaseModel, Field |
| 59 | + |
| 60 | +class GateResult(BaseModel): |
| 61 | + gate: str |
| 62 | + status: GateStatus |
| 63 | + failures: list[Failure] = Field(default_factory=list) |
| 64 | + duration_ms: int = 0 |
| 65 | +``` |
| 66 | + |
| 67 | +Bad: |
| 68 | +```python |
| 69 | +# Don't use raw dicts for gate results |
| 70 | +result = {"gate": "ruff", "status": "pass", "failures": []} |
| 71 | + |
| 72 | +# Don't use dataclasses — this project uses Pydantic |
| 73 | +@dataclass |
| 74 | +class GateResult: |
| 75 | + gate: str |
| 76 | +``` |
| 77 | + |
| 78 | +## Git Workflow |
| 79 | + |
| 80 | +- Branch from `main` |
| 81 | +- Conventional commits: `feat:`, `fix:`, `test:`, `docs:`, `chore:` |
| 82 | +- Run `pytest` and `ruff check` before pushing |
| 83 | +- JSON schemas in `schemas/` must stay in sync with Pydantic models in `models.py` |
| 84 | + |
| 85 | +## Boundaries |
| 86 | + |
| 87 | +**Always:** |
| 88 | +- Run `pytest` after modifying source files |
| 89 | +- Keep Pydantic v2 as the modeling library |
| 90 | +- Maintain Python 3.10+ compatibility |
| 91 | +- Update JSON schemas when changing Pydantic models |
| 92 | +- Use `from __future__ import annotations` in every module |
| 93 | + |
| 94 | +**Ask first:** |
| 95 | +- Adding new runtime dependencies (currently only pydantic + tomli) |
| 96 | +- Adding new gate types (ruff/pyright/pytest are the current three) |
| 97 | +- Changing exit codes in `constants.py` |
| 98 | +- Modifying the repair loop bounds or retry logic |
| 99 | +- Changing artifact output format (breaks downstream consumers) |
| 100 | + |
| 101 | +**Never:** |
| 102 | +- Execute subprocess commands in tests (all gate outputs are mocked) |
| 103 | +- Use dataclasses instead of Pydantic models |
| 104 | +- Remove or weaken the bounded repair loop (max-attempts is a safety constraint) |
| 105 | +- Commit real project output to `demo/artifacts/` (use synthetic examples) |
| 106 | +- Break JSON schema backward compatibility without a version bump |
0 commit comments