# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview "Thought" is a Rust CLI application for real-time streaming and posting to the ATProto network using `stream.thought.blip` records. It functions like an IRC client for Bluesky, featuring a terminal UI (TUI) for live message streaming. **Key Technology Stack:** - Rust with async/await (Tokio runtime) - ATProto API for authentication and posting - Jetstream WebSocket for real-time firehose - Ratatui for terminal UI - Custom record type: `stream.thought.blip` ## Building and Running ```bash # Build (development) cargo build # Build (release) cargo build --release # Run tests cargo test # Lint cargo clippy # Run the CLI ./target/release/thought # Login first-time use ./target/release/thought login # Main TUI mode (recommended) ./target/release/thought stream ``` ## Architecture ### Module Structure - **main.rs**: CLI entry point, command routing, and authentication setup - **client.rs**: ATProto HTTP client for authentication and posting blips - **credentials.rs**: Secure credential and session storage (platform-specific config directories) - **jetstream.rs**: WebSocket client for Jetstream firehose, DID resolution, and message filtering - **tui.rs**: Ratatui-based terminal UI with scrollable message feed - **interactive.rs**: Coordinator for TUI and simple REPL modes ### Authentication Flow 1. User provides handle/email and app password via `thought login` 2. Credentials stored in platform config directory (macOS: `~/Library/Application Support/com.thoughtstream.think/`) 3. Session tokens (accessJwt/refreshJwt) cached separately in `session.json` 4. Token refresh handled transparently by `create_authenticated_client()` in main.rs:133 5. Failed refresh triggers re-login with stored credentials **Important**: Session management uses both `credentials.json` (username/password/PDS URI) and `session.json` (JWT tokens). The client automatically refreshes tokens before operations. ### Real-time Message Flow 1. TUI spawns Jetstream listener in background task 2. Listener connects to `wss://jetstream2.us-west.bsky.network/subscribe` with collection filter 3. Incoming commits filtered for `stream.thought.blip` collection and "create" operations 4. DIDs resolved to handles via `app.bsky.actor.getProfile` (with caching) 5. Messages sent through mpsc channel to TUI for rendering 6. User's own messages filtered out using stored DID ### TUI Rendering - Messages displayed in **reverse chronological order** (newest first) - Scrollable with arrow keys/PageUp/PageDown - Auto-scrolls to bottom when at offset 0 - User's own posts styled in bold green - Connection status tracked via channel activity - Maximum 1000 messages buffered ## Development Notes ### Credential Storage Paths - macOS: `~/Library/Application Support/com.thoughtstream.think/` - Linux: `~/.config/thoughtstream/think/` - Windows: `%APPDATA%\thoughtstream\think\` ### Token Refresh Logic The client implements automatic token refresh (client.rs:106-137): 1. Attempt operation with current access token 2. On 401/ExpiredToken error, call `refresh_session()` 3. Retry operation with new token 4. If refresh fails, clear session and prompt re-login ### Jetstream Connection - Attempts simple connection first, then falls back to collection-filtered URL - Reconnects with 5-second delay on failure - Uses User-Agent: `think-cli/0.1.0` - Filters messages on client side even with server-side collection filter ### Publishing Blips Records posted with structure: ```json { "$type": "stream.thought.blip", "content": "", "createdAt": "" } ``` Posted to `com.atproto.repo.createRecord` with user's DID as repo. ## Note on Julia Dependencies The `Project.toml` and `Manifest.toml` files are unrelated to the Rust project—likely leftover artifacts or separate experiments (Franklin static site generator). The actual Rust dependencies are in `Cargo.toml`.