Files
roro9stack/docs/milestones/G1.md
T
twislaandClaude Opus 5.5 2d384f5cff G1 step 1: gemini get, and two TLS connections measured
`gemini get <url>` fetches on a short-lived task (a handshake would trip
the main loop's watchdog; an idle client should cost no stack) and
reports the header, size, certificate fingerprint and heap. First page:
geminiprotocol.net, 20 text/gemini, 1,184 bytes in 0.7-1.1 s.

With IRC connected over TLS, a fetch dips to about 24 KB free during its
handshake, about 36-40 KB after it; nothing leaks. Antenna is down, so
the default aggregator becomes Cosmos.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
2026-10-05 00:27:05 +02:00

52 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# G1 — Gemini client
**Goal:** browse Geminispace from the Cardputer: fetch and read gemtext over TLS, follow links, answer input prompts, keep bookmarks, and save pages to the SD card to read later, offline. A side milestone between M2 and M3, tagged v0.5.0 when done.
Gemini (geminiprotocol.net): one request per TLS connection on port 1965, the request is the URL and CRLF, the response a `<status> <meta>` header line, then the body. Most capsules use self-signed certificates: trust on first use is the norm.
## Decisions (design round 2026-10-05)
| # | Decision |
|---|---|
| Q70 | A milestone of its own, **G1**, before M3: plan, tests first, measured on the device, tagged v0.5.0. |
| Q71 | **TOFU:** the first certificate seen for a host is pinned (SHA-256, in NVS). If it changes, the page isn't shown; a dialog shows both fingerprints and asks whether to trust the new one. Self-signed or expired certificates are fine; only a change counts. |
| Q72 | Responses: 1x input (11 hidden, for passwords), 2x content, up to 5 redirects (3x), 4x/5x errors with the server's message. 6x (client certificates): "not supported". |
| Q73 | `text/gemini` is rendered, other `text/*` shown as plain text. Anything else can be saved to `/gemini/downloads/`, not shown. |
| Q74 | Up to **64 KB on screen**, larger pages truncated with a notice. Saving streams to the card, so a larger page is saved whole. |
| Q75 | Gemtext rendering: text wrapped to the 40-column screen; `#`/`##`/`###` headings in bold and accent; `*` lists with bullets; `>` quotes indented and muted; preformatted blocks unwrapped, Left/Right to scroll; `=>` links with their label, numbered. |
| Q76 | Up/Down scroll; Tab and Shift+Tab move between links; Enter follows; Backspace goes back; `g` opens the address line. Links to other protocols show their URL and aren't followed. |
| Q77 | Back history of 20 URLs in RAM, with scroll positions; going back refetches (or reopens a Saved Page). **Bookmarks** in `/gemini/bookmarks.gmi` (a gemtext page, shown on the start page); `b` adds the current page. Without a card, a built-in start page. |
| Q78 | Start page: bookmarks, then Saved Pages, then defaults: geminiprotocol.net, a search engine (kennedy.gemi.dev), an aggregator (Cosmos; Antenna was down when measured). |
| Q79 | UTF-8 decoded; characters outside the Latin-1 fonts shown as `?`. |
| Q80 | IRC and Gemini can run together: each fetch opens one connection, reads and closes it. If there isn't memory for a second TLS connection, the fetch fails with a clear message and IRC is untouched. Measured in step 1. |
| Q81 | Debug aid: `gemini get <url>` prints the status, MIME type, size, certificate fingerprint and the first lines. URL resolution (RFC 3986), the response header and gemtext parsing are host-tested. |
| Q82 | `s` saves the page on screen as a **Saved Page**: `/gemini/saved/<host>/<path>.gmi`, the gemtext as received plus a first line with its URL and save date. Saving again replaces it, and says so. |
| Q83 | `S` saves the page and the pages it links to, one level deep: gemtext only, same host only, at most 30 pages, in the background with a progress Toast. |
| Q84 | The start page lists Saved Pages, newest first, grouped by capsule; they open with no network. In a Saved Page, a link to another Saved Page opens the saved copy; other links fetch online if Wi-Fi is up, or say "not saved, offline". A Saved Page shows when it was saved; `r` refreshes it. |
| Q85 | Saved Pages are deleted from the App only (`d`, with confirmation), never by Storage Clean-up's age rules, like Notes. |
## Measured (step 1)
- `gemini://geminiprotocol.net/`: `20 text/gemini`, 1,184 bytes, TLS handshake 0.7–1.1 s, whole fetch 0.7–1.1 s; kennedy.gemi.dev 1.9 s. The fetch task's stack peaks at about 3.6 KB of 6.
- **Heap, Debug Build, IRC connected over TLS:** about 68 KB free before a fetch. After the handshake the fetch holds about 32 KB (36–40 KB left); the handshake itself (certificate chain parsed with the 16 KB receive buffer allocated) dips to about **24 KB** for a second or two. Nothing leaks: the heap after matches the heap before.
- Antenna (`warmedal.se`) doesn't answer, from the PC either; the default aggregator becomes Cosmos (`gemini://skyjake.fi/~Cosmos/`, which redirects to `cosmos.skyjake.fi`).
## Done when
- `gemini get gemini://geminiprotocol.net/` prints the header, size and fingerprint on the console.
- The Gemini App opens the start page, follows links (relative ones included), goes back, and follows redirects.
- An input prompt (e.g. a search) takes a query and shows the results.
- A changed certificate stops the page and asks.
- `s` saves a page, `S` a page and its links; with Wi-Fi off, Saved Pages open and their saved links work.
- Bookmarks are added with `b` and listed on the start page.
- With IRC connected over TLS, a fetch still works, and the free heap stays above 40 KB.
## Work breakdown
1. **Two TLS connections:** measure the heap with IRC connected while a Gemini fetch runs.
2. **Parsers** (host-tested): URL parsing and relative resolution, the response header, gemtext lines.
3. **Fetch** on its own task, with TOFU and `gemini get`.
4. **Gemini App:** rendering, scrolling, links, history, the address line.
5. **Input prompts, redirects, bookmarks, downloads.**
6. **Saved Pages,** then saving with linked pages.