|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +This repository contains the **API Enhancement Proposals (AEPs)** — the design |
| 4 | +specification documents for the [AEP project](https://aep.dev). It is a |
| 5 | +content-driven repository: the primary artifacts are Markdown/Jinja2 documents |
| 6 | +and YAML metadata, not application code. |
| 7 | + |
| 8 | +## Repository layout |
| 9 | + |
| 10 | +``` |
| 11 | +aep/general/<NNNN>/ # One directory per AEP (zero-padded, 4-digit number) |
| 12 | + aep.yaml # AEP metadata (id, state, slug, category, etc.) |
| 13 | + aep.md.j2 # AEP content (Markdown + Jinja2 template syntax) |
| 14 | +config/ # Site configuration (hero, header, urls, site) |
| 15 | +scripts/ # Tooling: fix.py, validate_links.py, build.sh, serve.sh |
| 16 | +pages/general/ # Static site pages (adopting, faq, licensing, etc.) |
| 17 | +blog/ # Blog posts |
| 18 | +.github/workflows/ # CI: lint.yaml, test.yaml, publish_site.yaml |
| 19 | +``` |
| 20 | + |
| 21 | +## AEP file structure |
| 22 | + |
| 23 | +Every AEP lives in `aep/general/<NNNN>/` and contains exactly two files: |
| 24 | + |
| 25 | +### `aep.yaml` — metadata |
| 26 | + |
| 27 | +Required fields: |
| 28 | + |
| 29 | +- `id`: integer AEP number (no zero-padding) |
| 30 | +- `state`: one of `draft`, `reviewing`, `approved`, `final`, `replaced`, |
| 31 | + `withdrawn` |
| 32 | +- `slug`: URL-friendly short name |
| 33 | +- `created`: ISO-8601 date (`yyyy-mm-dd`) |
| 34 | +- `placement.category`: one of `meta`, `general`, `resources`, |
| 35 | + `standard-methods`, `fields`, `types`, `design-patterns`, `batch-methods`, |
| 36 | + `best-practices`, `protobuf` |
| 37 | + |
| 38 | +Optional fields: `updated`, `placement.order`, `redirect_from`, `js_scripts`. |
| 39 | + |
| 40 | +### `aep.md.j2` — content |
| 41 | + |
| 42 | +Markdown with Jinja2 template directives. Key conventions: |
| 43 | + |
| 44 | +- Starts with a single `#` title (a noun, not an imperative). |
| 45 | +- Introduction paragraph (no heading) → `## Guidance` section. |
| 46 | +- Optional trailing sections in order: `## Rationale`, `## History`, |
| 47 | + `## Further reading`, `## Changelog`. |
| 48 | +- Only use heading levels `##` and `###` (never `#` beyond the title). |
| 49 | +- Use RFC-2119 keywords (`**must**`, `**should**`, `**may**`) in lower-case |
| 50 | + bold. |
| 51 | +- Use `{% tab proto %}` / `{% tab oas %}` / `{% endtabs %}` for |
| 52 | + protocol-specific examples. |
| 53 | +- Use `{% sample '<path>', '<selector>' %}` to include code from example files. |
| 54 | +- Cross-reference AEPs as `AEP-N` (no zero-padding) in prose, with links using |
| 55 | + relative paths like `./0008.md` or `../0008.md`. |
| 56 | +- Links must NOT end in `.md` (the linter strips `.md` suffixes). Exception: |
| 57 | + external GitHub links. |
| 58 | +- Do not use self-reference links like `[aep-123][aep-123]` — use plain text. |
| 59 | +- Do not use reference-style links with AEP identifiers like |
| 60 | + `[aep-123]: ./0123`. |
| 61 | +- Wrap reference-style link definitions that would break prettier in |
| 62 | + `<!-- prettier-ignore-start -->` / `<!-- prettier-ignore-end -->` blocks. |
| 63 | + |
| 64 | +## Formatting and linting |
| 65 | + |
| 66 | +Formatting is enforced by CI. Always run before committing: |
| 67 | + |
| 68 | +```bash |
| 69 | +make lint |
| 70 | +``` |
| 71 | + |
| 72 | +This runs three checks: |
| 73 | + |
| 74 | +1. **Prettier** (`npm run check`): Markdown/YAML/JSON formatting. |
| 75 | + - `printWidth: 79`, `proseWrap: always`, `singleQuote: true`, |
| 76 | + `trailingComma: es5`. |
| 77 | + - `.md.j2` files are parsed as Markdown. |
| 78 | +2. **`scripts/fix.py`**: Validates and fixes AEP-specific link rules. |
| 79 | + - No `.md` suffixes in internal links. |
| 80 | + - All AEP cross-references point to existing AEPs. |
| 81 | + - No self-reference links, no AEP-identifier reference-style links. |
| 82 | + - HTTP URLs are well-formed. |
| 83 | +3. **`scripts/validate_links.py`**: Read-only link validation (same rules as |
| 84 | + fix.py but never modifies files). |
| 85 | + |
| 86 | +Use `make check` for a read-only lint pass (CI uses this). |
| 87 | + |
| 88 | +## Development |
| 89 | + |
| 90 | +### Prerequisites |
| 91 | + |
| 92 | +- Node.js + npm |
| 93 | +- Python 3 |
| 94 | + |
| 95 | +### Install dependencies |
| 96 | + |
| 97 | +```bash |
| 98 | +make install # runs npm install |
| 99 | +``` |
| 100 | + |
| 101 | +### Local preview |
| 102 | + |
| 103 | +```bash |
| 104 | +./scripts/serve.sh |
| 105 | +``` |
| 106 | + |
| 107 | +This clones the [site-generator](https://github.com/aep-dev/site-generator) (if |
| 108 | +not already present as a sibling directory), builds the site, and starts a dev |
| 109 | +server on port 4321. |
| 110 | + |
| 111 | +### Build |
| 112 | + |
| 113 | +```bash |
| 114 | +./scripts/build.sh |
| 115 | +``` |
| 116 | + |
| 117 | +Builds the full site including the site-generator, api-linter, and |
| 118 | +aep-openapi-linter (uses sibling directories if present, otherwise clones to |
| 119 | +`/tmp`). |
| 120 | + |
| 121 | +## CI workflows |
| 122 | + |
| 123 | +| Workflow | Trigger | What it does | |
| 124 | +| ------------------- | ----------- | ------------------------------------------------- | |
| 125 | +| `lint.yaml` | PR → main | `make check` (prettier + fix.py + validate_links) | |
| 126 | +| `test.yaml` | PR → main | `./scripts/build.sh` (full site build) | |
| 127 | +| `publish_site.yaml` | push → main | Triggers site-generator repository dispatch | |
| 128 | + |
| 129 | +## Content conventions |
| 130 | + |
| 131 | +- AEPs should be concise — roughly two printed pages. |
| 132 | +- A single AEP covers a single topic. |
| 133 | +- API design examples should be presented in both OpenAPI (OAS 3.1) and |
| 134 | + protocol buffers. |
| 135 | +- Use snake_case for parameter and property names in examples. |
| 136 | +- Error codes in prose use the format `{error_code} / {http_status_code}` (e.g. |
| 137 | + `OK / 200`). |
| 138 | +- Example files (`example.oas.yaml`, `example.proto`) in `aep/general/` are |
| 139 | + code-generated by [aepc](https://github.com/aep-dev/aepc) — do not edit them |
| 140 | + by hand. |
| 141 | + |
| 142 | +## Common pitfalls |
| 143 | + |
| 144 | +- **Don't link to `.md` files** in AEP content (except external GitHub links). |
| 145 | + Links like `./0131.md` will be auto-fixed to `./0131` by `fix.py`, but will |
| 146 | + fail `make check`. |
| 147 | +- **Don't forget `make lint`** before committing. Prettier reformats prose |
| 148 | + wrapping at 79 columns, and fix.py catches link issues. |
| 149 | +- **Don't edit `example.oas.yaml` or `example.proto`** — these are generated |
| 150 | + from aepc. |
| 151 | +- **Zero-pad directory names** but not prose references. Directory: `0008/`. |
| 152 | + Prose: `AEP-8`. |
0 commit comments