From dc9b0e14ceb66995ae08660667286b34b74d11fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Martin?= Date: Mon, 5 Oct 2026 00:18:01 +0200 Subject: [PATCH] G1 design: Gemini client plan, glossary (Capsule, Saved Page) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT --- CONTEXT.md | 8 ++++++++ docs/milestones/G1.md | 45 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 docs/milestones/G1.md diff --git a/CONTEXT.md b/CONTEXT.md index 65e3324..de4b688 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -40,6 +40,14 @@ _Avoid_: DM (in docs), private message Rebroadcasting another Node's packet so it travels further across the mesh. _Avoid_: forwarding, repeating +**Capsule**: +A Gemini site: everything served by one host on Geminispace. +_Avoid_: site, server (when the content is meant) + +**Saved Page**: +A Gemini page kept on the SD card to read offline, with the URL it came from and when it was saved. Kept until the user deletes it; Storage Clean-up never offers it. +_Avoid_: cache, download (a download is a non-text file saved from Gemini) + **GNSS Service**: The Service that owns the GNSS receiver on the Cap: it reads its NMEA sentences in the background and holds the current Fix, position, time and satellites. _Avoid_: GPS (GPS is one constellation among several) diff --git a/docs/milestones/G1.md b/docs/milestones/G1.md new file mode 100644 index 0000000..78ed937 --- /dev/null +++ b/docs/milestones/G1.md @@ -0,0 +1,45 @@ +# 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 ` ` 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 (Antenna). | +| 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 ` 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//.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. | + +## 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.