docs: correct READMEs for packages (#436)

Drew Smirnoff created

Change summary

backend/README.md | 45 ++++++++++++++++++++++++++++++++++++++++
clib/README.md    | 26 +++++++++++++++++++++++
config/README.md  | 16 ++++++++++++++
fetcher/README.md |  5 ++++
plugin/README.md  | 55 +++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 147 insertions(+)

Detailed changes

backend/README.md 🔗

@@ -0,0 +1,45 @@
+# backend
+
+The `backend` package defines a unified `Provider` interface for multi-protocol email support and provides three protocol implementations: IMAP, JMAP, and POP3.
+
+## Architecture
+
+This package acts as an abstraction layer, allowing the rest of the application to interact with mail servers through a consistent interface regardless of the underlying protocol. Implementations self-register at init time via `RegisterBackend`, and the factory function `New()` creates the right provider based on the account's `Protocol` field (defaults to `"imap"`).
+
+### Provider interface
+
+The `Provider` interface composes five sub-interfaces:
+
+| Interface | Methods | Purpose |
+|-----------|---------|---------|
+| `EmailReader` | `FetchEmails`, `FetchEmailBody`, `FetchAttachment` | Retrieve email lists, bodies, and raw attachments |
+| `EmailWriter` | `MarkAsRead`, `DeleteEmail`, `ArchiveEmail`, `MoveEmail` | Modify email state and location |
+| `EmailSender` | `SendEmail` | Send outgoing mail |
+| `FolderManager` | `FetchFolders` | List available mailboxes |
+| `Notifier` | `Watch` | Real-time push notifications for mailbox changes |
+
+Backends that don't support an operation return `ErrNotSupported`.
+
+## Protocols
+
+### IMAP (`backend/imap`)
+
+Wraps the existing `fetcher` and `sender` packages behind the `Provider` interface. IMAP IDLE is handled externally in `main.go`, so `Watch()` returns `ErrNotSupported`.
+
+### JMAP (`backend/jmap`)
+
+Native JMAP implementation (RFC 8620 / RFC 8621) using `go-jmap`. Supports OAuth2 and Basic Auth, real-time push via JMAP EventSource, and full mailbox operations including send (via `EmailSubmission`). JMAP string IDs are hashed to `uint32` UIDs for interface compatibility.
+
+### POP3 (`backend/pop3`)
+
+POP3 + SMTP implementation. Inherently limited to a single INBOX folder, no read flags, no move/archive, and no push notifications. Uses the `sender` package for outgoing mail.
+
+## Files
+
+| File | Description |
+|------|-------------|
+| `backend.go` | Core interfaces and data types (`Provider`, `Email`, `Attachment`, `Folder`, `OutgoingEmail`, `NotifyEvent`, `Capabilities`) |
+| `factory.go` | Protocol registry and `New()` factory function |
+| `imap/imap.go` | IMAP provider — adapter over `fetcher` and `sender` packages |
+| `jmap/jmap.go` | JMAP provider — native implementation with session management and mailbox caching |
+| `pop3/pop3.go` | POP3 provider — per-connection model with UIDL-based UID hashing |

clib/README.md 🔗

@@ -23,6 +23,32 @@ Image decoding and PNG re-encoding using [stb_image](https://github.com/nothings
 
 Files: `imgconv.c`, `imgconv.h`, `imgconv.go`, `stb_image.h`, `stb_image_write.h`
 
+### htmlconv
+
+Single-pass HTML-to-structured-elements parser. Takes raw HTML and returns a slice of `HTMLElement` values representing headings, links, images, blockquotes, tables, and text. Used by the email view to render HTML emails in the terminal without a full DOM.
+
+- `HTMLToElements()` — parses HTML into structured elements with type, text, and up to two attributes (e.g., `href`/`src`, `alt`/`cite`).
+
+Files: `htmlconv.c`, `htmlconv.h`, `htmlconv.go`
+
+### markdown
+
+Markdown-to-HTML conversion using [md4c](https://github.com/mity/md4c) (vendored). Supports GitHub-flavored features: tables, strikethrough, task lists, and permissive autolinks.
+
+- `MarkdownToHTML()` — converts Markdown bytes to HTML bytes.
+
+Files: `md4c.c`, `md4c.h`, `md4c-html.c`, `md4c-html.h`, `markdown.go`
+
+## Pure Go fallbacks
+
+Every function has a `_nocgo.go` counterpart (build tag `!cgo`) that provides the same API using pure Go libraries:
+
+| C implementation | Go fallback |
+|-----------------|-------------|
+| `base64wrap.go` | Manual string builder |
+| `imgconv.go` (stb_image) | `image/png`, `image/jpeg`, `image/gif` |
+| `htmlconv.go` | `goquery` DOM parsing |
+| `markdown.go` (md4c) | `goldmark` |
 
 ## Adding new C code
 

config/README.md 🔗

@@ -21,4 +21,20 @@ All cache files use JSON serialization with restrictive file permissions (`0600`
 | `cache.go` | Email, contacts, and drafts caching. Provides CRUD operations for `EmailCache`, `ContactsCache` (with search and frequency-based ranking), and `DraftsCache` (with save/delete/get operations). |
 | `folder_cache.go` | Caches IMAP folder listings per account and per-folder email metadata. Stores folder names to avoid repeated IMAP `LIST` commands, and caches email headers per folder for fast navigation. |
 | `signature.go` | Loads and saves the user's email signature from `~/.config/matcha/signature.txt`. |
+| `oauth.go` | OAuth2 integration — token retrieval, authorization flow launcher, and embedded Python helper extraction. |
+| `oauth_script.py` | Embedded Gmail OAuth2 helper script (browser-based auth, token refresh, secure storage). |
 | `config_test.go` | Unit tests for configuration logic. |
+
+## OAuth2 / XOAUTH2
+
+Accounts with `auth_method: "oauth2"` use Gmail's XOAUTH2 mechanism instead of passwords. The flow works across three layers:
+
+1. **`config/oauth.go`** — Go-side orchestration. Extracts the embedded Python helper to `~/.config/matcha/oauth/`, invokes it to run the browser-based authorization flow (`RunOAuth2Flow`) or to retrieve a fresh access token (`GetOAuth2Token`). The `IsOAuth2()` method on `Account` checks the auth method.
+
+2. **`config/oauth_script.py`** — Embedded Python script that handles the full OAuth2 lifecycle:
+   - `auth` — Opens a browser for Google authorization, captures the callback on `localhost:8189`, exchanges the code for tokens, and saves them to `~/.config/matcha/oauth_tokens/`.
+   - `token` — Returns a fresh access token, automatically refreshing if expired (with a 5-minute buffer).
+   - `revoke` — Revokes tokens with Google and deletes local storage.
+   - Client credentials are stored in `~/.config/matcha/oauth_client.json`.
+
+3. **`fetcher/xoauth2.go`** — Implements the XOAUTH2 SASL mechanism (`sasl.Client` interface) for IMAP/SMTP authentication. Formats the initial response as `user=<email>\x01auth=Bearer <token>\x01\x01` per Google's XOAUTH2 protocol spec.

fetcher/README.md 🔗

@@ -13,3 +13,8 @@ This package is the IMAP client layer for Matcha. It:
 - Supports S/MIME decryption (opaque and enveloped) and detached signature verification
 - Provides mailbox operations: delete (expunge), archive (move), and folder-to-folder moves
 - Exposes both mailbox-specific and convenience functions (e.g., `FetchEmails` defaults to INBOX)
+- Supports XOAUTH2 SASL authentication for Gmail OAuth2 accounts (see `xoauth2.go`)
+
+## XOAUTH2
+
+The `xoauth2.go` file implements the XOAUTH2 SASL mechanism as a `sasl.Client`. When an account uses `auth_method: "oauth2"`, the fetcher calls `config.GetOAuth2Token()` to get a fresh access token, then authenticates the IMAP connection using this SASL client instead of a password. The initial response follows Google's XOAUTH2 protocol: `user=<email>\x01auth=Bearer <token>\x01\x01`.

plugin/README.md 🔗

@@ -0,0 +1,55 @@
+# plugin
+
+Lua-based plugin system for extending Matcha. Plugins are loaded from `~/.config/matcha/plugins/` and run inside a sandboxed Lua VM (no `os`, `io`, or `debug` libraries).
+
+## How it works
+
+The `Manager` creates a Lua VM at startup, registers the `matcha` module, and loads all plugins from the user's plugins directory. Plugins can be either a single `.lua` file or a directory with an `init.lua` entry point.
+
+Plugins interact with Matcha by registering callbacks on hooks:
+
+```lua
+local matcha = require("matcha")
+
+matcha.on("email_received", function(email)
+    matcha.log("New email from: " .. email.from)
+    matcha.notify("New mail!", 3)
+end)
+```
+
+## Lua API (`matcha` module)
+
+| Function | Description |
+|----------|-------------|
+| `matcha.on(event, callback)` | Register a callback for a hook event |
+| `matcha.log(msg)` | Log a message to stderr |
+| `matcha.notify(msg [, seconds])` | Show a temporary notification in the TUI (default 2s) |
+| `matcha.set_status(area, text)` | Set a persistent status string for a view area (`"inbox"`, `"composer"`, `"email_view"`) |
+
+## Hook events
+
+| Event | Callback argument | Description |
+|-------|-------------------|-------------|
+| `startup` | — | Matcha has started |
+| `shutdown` | — | Matcha is exiting |
+| `email_received` | Lua table with `uid`, `from`, `to`, `subject`, `date`, `is_read`, `account_id`, `folder` | New email arrived |
+| `email_viewed` | Same as `email_received` | User opened an email |
+| `email_send_before` | Table with `to`, `cc`, `subject`, `account_id` | About to send an email |
+| `email_send_after` | Same as `email_send_before` | Email sent successfully |
+| `folder_changed` | Folder name (string) | User switched folders |
+| `composer_updated` | Table with `body`, `body_len`, `subject`, `to` | Composer content changed |
+
+## Available plugins
+
+The following example plugins ship in `~/.config/matcha/plugins/`:
+
+- `email_age.lua`
+- `recipient_counter.lua`
+
+## Files
+
+| File | Description |
+|------|-------------|
+| `plugin.go` | Plugin manager — Lua VM setup, plugin discovery and loading, notification/status state |
+| `hooks.go` | Hook definitions, callback registration, and hook invocation helpers |
+| `api.go` | `matcha` Lua module registration (`on`, `log`, `notify`, `set_status`) |