# AGENTS.md — Working agreement for AI coding agents on this repo
> **Loaded automatically by Claude Code, Cursor, Aider, and most other
> agent harnesses.** Every contributor (human or AI) MUST read this file
> before changing code. Violations are merge-blockers.
---
## 1. Ground rules (hard requirements)
1. **Quality over quantity.** One feature done well beats three half-baked
features. If you cannot finish something to the standard below in the
current session, leave it out and open a tracking issue instead.
2. **Verify "latest" against live sources.** Before adding or upgrading any
dependency, language version, GitHub Action, or framework, confirm the
current stable release from an authoritative source:
- Rust crates: `cargo search <crate> --limit 1` or
`curl -s https://crates.io/api/v1/crates/<crate> | jq -r .crate.max_stable_version`
- GitHub Actions: check the action's repo `Releases` page (or
`gh release view --repo owner/repo --json tagName`).
- Rust toolchain: `https://forge.rust-lang.org/infra/channel-layout.html`
or `rustup check`.
- Do **not** trust prior agent memory for version numbers.
3. **Accessibility is the bare minimum, not a stretch goal.** Every UI
surface (desktop GUI, web pages, generated docs site, CLI output) MUST
meet **WCAG 2.2 Level AAA** at a minimum:
- Text contrast ≥ 7:1 against its background (≥ 4.5:1 for large text).
- All information conveyed by colour MUST also have a textual cue
(`[PASS]`, `[FAIL]`, icons with labels, etc.). Colour is never the
only signal.
- Full keyboard operability with a visible focus indicator.
- No content flashes more than 3× per second.
- Form fields have visible, programmatic labels (not placeholder-only).
- Live regions / status messages announced to assistive tech (egui ⇒
AccessKit, web ⇒ `aria-live`).
- Honour `prefers-reduced-motion` and `prefers-contrast`.
4. **Dark + light mode, on every OS, always.** Every UI MUST detect and
follow the operating-system appearance setting (Windows registry,
macOS `AppleInterfaceStyle`, GNOME/KDE/Cosmic, web
`prefers-color-scheme`). A manual override MUST also be available, and
the chosen theme MUST persist between sessions.
5. **No shortcuts, even if they look like overkill.** Hand-rolled JSON
parser when serde exists? No. Single-file 3000-line module to "save
time"? No. The right tool, modular code, real tests, real error
handling. If a solution feels too clever, it is wrong.
6. **Commit early, commit often, atomic commits.** Every logically
independent change is its own commit with a [Conventional Commits]
message (`feat:`, `fix:`, `chore:`, `docs:`, `refactor:`, `test:`,
`ci:`, `perf:`). Never bundle unrelated changes. This is what lets us
`git revert` cleanly when something breaks. Push to a feature branch,
open a PR, let CI run; merge only when green.
7. **Polish counts.** GUI spacing, web typography, CLI output alignment,
error message wording — all of it is part of the product. If it looks
amateur, it is broken.
8. **Credentials never touch the config file, logs, or eframe state.**
Passwords, OAuth bearer tokens, API keys, and similar secrets live
in process memory for the current session only — OR in an OS
keychain via `src/keystore.rs`, which is the **one** approved
persistent store. The OS keychain provides real at-rest encryption
gated by the OS login / unlock prompt; our own TOML files do not.
Enforced at the type level via `#[serde(skip)]` on
`Profile::password` and `::oauth_token`, behaviourally by
`tests/config_roundtrip.rs::save_never_writes_credentials_even_when_set`,
and the keychain code itself is feature-gated so a CLI-only build
can ship without ever linking the keyring crate. Removing or
weakening any of those is a merge blocker.
[Conventional Commits]: https://www.conventionalcommits.org/
---
## 2. Stack of record (so agents don't churn it)
| Language | Rust (edition 2021) | Safety, single static binary, modern tooling. |
| MSRV | 1.92 | Floor set by the egui 0.34 ecosystem. |
| TLS | `rustls` + ring | Pure Rust, no OpenSSL on host. |
| SMTP | `lettre` 0.11+ | De-facto Rust SMTP client. |
| IMAP / POP3 | hand-rolled on rustls | Owns the wire trace for diagnostics. |
| CLI parsing | `clap` 4 derive | Standard. |
| Config | `serde` + `toml` | Human-editable, IT-friendly. |
| Logging | `tracing` family | One subscriber, many sinks (CLI, GUI, file). |
| Desktop GUI | `eframe`/`egui` | Single binary, AccessKit, OS theme follow. |
| Web (if needed) | not yet decided | When added: must meet rule #3 from day one. |
Before changing any of the above, open an issue with rationale; never
silently swap.
---
## 3. Definition of Done for any change
A pull request is **only** ready to merge when **all** of these are true:
- [ ] Builds clean on Linux + macOS + Windows in CI.
- [ ] `cargo fmt --all -- --check` passes.
- [ ] `cargo clippy --all-targets --all-features -- -D warnings` passes.
- [ ] `cargo test --all-features` passes.
- [ ] `cargo deny check` passes (advisories, licenses, sources, bans).
- [ ] If user-facing: screenshots in dark **and** light mode attached to
the PR, plus a paragraph describing the keyboard path through the
new UI.
- [ ] If protocol-affecting: example real-world server diagnostic added
to `tests/diagnostics.rs`.
- [ ] `CHANGELOG.md` updated under `## [Unreleased]`.
- [ ] No `unwrap()` / `expect()` in non-test code without a
`// SAFETY:`-style comment justifying it.
- [ ] No new dependency added without verifying it is the latest stable
(rule #2) and that `cargo deny` accepts its licence.
---
## 4. Commit / branch workflow
```
main ← protected, always green, always shippable
└── feat/x ← short-lived branches, squash-merge via PR
```
- One PR = one concern.
- Commit message body explains *why*, not *what* (the diff shows what).
- Reference issues with `Refs #N` or `Closes #N`.
- Tag releases with `vX.Y.Z`; CI then builds and publishes binaries +
the crate to crates.io.
---
## 5. When you (an AI agent) are blocked
- Do not invent API surfaces. Read the actual crate docs (`cargo doc
--open` or docs.rs) before guessing.
- If a build fails, paste the **exact** error in your reply and fix
the smallest possible thing first — do not refactor under cover of a
bug fix.
- If you broke something, `git status` and `git diff` before doing
anything else. If unsure, `git stash` and ask the user.
- Tell the user the truth, including "I can't verify X right now
because Y". Do not bluff.