commit dc15f71d5b581d239ad02d3a8087f617e9f8a80d
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Tue, 25 Aug 2026 21:10:03 -0700
Plan Charmbracelet TUI implementation
Diffstat:
1 file changed, 78 insertions(+), 0 deletions(-)
diff --git a/doc/plan/charmbracelet-tui.md b/doc/plan/charmbracelet-tui.md
@@ -0,0 +1,78 @@
+# Charmbracelet TUI implementation plan
+
+## Architecture
+
+The Go module is `github.com/ryan/gotextlog`. The executable is `cmd/textlog`.
+
+`internal/textlog` owns API v1.1 wire types and HTTP/SSE behavior. It exports a
+`Client` with methods for public/authenticated feeds, search, posts and replies,
+profiles and relationship collections, tags, authentication, account mutation,
+post mutation, moderation, and a reconnectable-consumer-friendly `Firehose`.
+Methods take `context.Context`; collection methods take `limit int` and
+`cursor string`. The TUI defines its own narrow service interface from these
+methods so model tests can use a fake.
+
+`internal/config` owns URL normalization, environment precedence, platform
+config paths, and atomic owner-only persistence. It exposes `Load(env)`,
+`Save(config, env)`, and `NormalizeBaseURL`.
+
+`internal/domain` owns note validation, relative timestamps, terminal-safe
+text, rich-text tokenization, ASCII-art detection, and reply-thread ordering.
+It consumes `internal/textlog` wire types and has no terminal framework state.
+
+`internal/tui` owns the Bubble Tea model, commands, navigation stack, async
+message handling, list/editor/menu state, rendering, key bindings, theme, and
+browser launch. API and persistence calls are commands. The root model remains
+the owner of navigation, current-user/session state, and global status.
+
+## W1: API client
+
+Files: `internal/textlog/types.go`, `internal/textlog/client.go`, and their
+`*_test.go` files.
+
+Deliver all JSON endpoints represented by the reference implementation, bearer
+headers, structured errors with Retry-After, URL encoding/query pagination, and
+SSE parsing that tolerates chunk boundaries and malformed events. The coarse
+test drives an `httptest.Server` through representative GET, mutation, error,
+and split firehose requests.
+
+Verification: `go test ./internal/textlog` and `go test -race ./internal/textlog`.
+
+Dependency: none.
+
+## W2: configuration and domain behavior
+
+Files: `internal/config/config.go`, `internal/config/config_test.go`,
+`internal/domain/domain.go`, and `internal/domain/domain_test.go`.
+
+Deliver environment-aware configuration with atomic mode-0600 persistence and
+the complete pure helper behavior from the reference, including Unicode note
+limits, link/reference tokenization, terminal whitespace safety, and cycle-safe
+reply ordering. Domain types import `internal/textlog`.
+
+Verification: `go test ./internal/config ./internal/domain`.
+
+Dependency: W1 types (both workstreams may proceed concurrently because their
+files are disjoint).
+
+## W3: Bubble Tea application and executable
+
+Files: `internal/tui/*.go`, `cmd/textlog/main.go`, root acceptance tests,
+`go.mod`, and `go.sum`.
+
+Start with a coarse Bubble Tea model test covering initial feed load, keyboard
+navigation into a note, reply composition and preview, successful publication,
+and back navigation. Implement responsive feed/search/thread/profile/tag/live,
+compose/login/account/settings/help screens; guest and authenticated tabs;
+cursor pagination; rich note rendering and target navigation; mutations and
+moderation; SSE pause/retry; CLI flags and TTY checks. Use Bubble Tea, Bubbles,
+and Lip Gloss from Charmbracelet.
+
+Verification: `go test ./...`, `go test -race ./...`, and `go build ./cmd/textlog`.
+
+Dependency: W1 and W2. Integration is done in this workstream.
+
+## Documentation and completion
+
+Add `README.md` with build, controls, configuration, and API coverage. Remove
+this plan after all tests and build pass; retain durable behavior in the README.