all repos — llm_aggregator @ e3e7be8461bb50a7fe674b4055286d34dddb0c5c

A CLI tool to aggregate RSS feeds and summarise them with LLMs

e3e7be84
docs: improve code documentation and clarify internal interfaces

- Add or expand Go doc comments for all exported types and functions
  - Document purpose, parameters, return values, and edge cases
  - Examples: NewLLMClient, ViperToRuntime, EncodingForModel, isZero
- Replace vague or outdated comments with precise behavior descriptions
  - Clarify feed fetching, content extraction, and webpage fallback
    logic
  - Explain signal handling, context cancellation, and timeout
    composition
- Remove redundant or misleading comments (e.g., obvious step-by-step
  remarks)
- Standardise progress logging interface documentation across
  implementations
  - SimpleLogger, NoopLogger, TUIProgress now have consistent doc
    strings
- Add inline explanations for non-obvious logic
  - Tokeniser caching, zero-value detection for CLI args, sort fallback
    to date
- Improve TUI model comments to reflect Bubbletea command pattern
  accurately
- Clean up whitespace and comment formatting for consistency
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Mon, 27 Apr 2026 13:00:19 +0200
97214a9c
docs: improve README and create USAGE.md

- Create a `USAGE.md` file to lighten the README
- Create a `BUILD.md` with detailed build instructions.
- Revise `README.md` to be more concise and punchy
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Mon, 27 Apr 2026 12:26:33 +0200
d3fad337
refactor: improve code quality, error handling, and test hygiene

- Standardise error handling and simplify error returns
  - Replace `fmt.Errorf` with `errors.New` for static error messages
  - Convert `extractArticle` to return `*Article` instead of `(*Article,
    error)`
  - Use `errors.As` for type assertion on
    `viper.ConfigFileNotFoundError`
- Enhance test suite with proper isolation and cleanup
  - Replace manual `os.Setenv`/`os.Unsetenv` with `t.Setenv` throughout
  - Remove unused test helpers (`writeTestFile`, `writeTempFile`,
    `contains`, `hasSuffix`)
  - Delete redundant `testFile` struct and `createFile` helpers
  - Fix deferred close error checks with `//nolint:errcheck` annotations
- Apply `//nolint:errcheck` to intentional error discards
  - stdout writes, file closes, and environment variable unset
    operations
  - Pipe writes in test stubs
- Simplify string formatting and concatenation
  - Replace `fmt.Sprintf` with direct string concatenation where
    appropriate
  - Use `strconv.Itoa` instead of `fmt.Sprintf("%d", ...)` in dry-run
    output
- Clean up dead code and unused constants
  - Remove unused `malformedRSSFeed` and `testRSSFeed` constants
  - Delete unused color gradient variables from TUI model
- Reorganize switch statements for clarity
  - Replace `if-else` chains with `switch` in feed source selection and
    TUI view
- Improve code documentation
  - Add explanatory comments to default constants
  - Document exported function behaviour
- Update HTTP method constant from `"GET"` to `http.MethodGet`
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Mon, 27 Apr 2026 12:07:53 +0200
29a4710e
feat: add LLM request timeout with `--timeout` flag

- Add configurable timeout for LLM API requests
  - CLI flag: `--timeout N` (seconds) with default 300
  - Config file: `timeout = N` in TOML
  - Environment variable: `LLM_AGGREGATOR_TIMEOUT`
  - Store timeout in `Runtime.LLMTimeout` and pass to `LLMClient`
- Implement timeout using `context.WithTimeout`
  - Derive timeout context from signal-handling parent context in
    `Execute()`
  - Both `SIGINT`/`SIGTERM` and timeout abort the request cleanly
  - Add error detection for "context deadline exceeded" → descriptive
    timeout message
- Update `LLMClient` constructor (`NewLLMClient`)
  - Add `timeoutSeconds` parameter; 0 defaults to `DefaultLLMTimeout`
    (300)
  - Rename internal field from `timeoutSeconds` to `llmTimeout` for
    clarity
- Add `DefaultLLMTimeout` constant in `internal/defaults`
- Update documentation
  - `README.md`: add `--timeout` flag and env var to tables
  - `docs/llm_aggregator.1`: add `--timeout` and correct misplaced
    `--system-prompt`
  - `docs/llm_aggregator.5`: add `timeout` field and env var
  - `docs/TESTING.md`: document new LLM client tests and coverage update
    (22%)
- Add unit tests for LLM client (`internal/llm`)
  - `TestNewLLMClientTimeout`: verify default and custom timeout values
  - `TestNewLLMClientDefaults`: confirm all defaults applied including
    timeout
  - `TestNewLLMClientRequiresAPIKey`: preserve existing validation test
- Update `CHANGELOG.md` for version 0.15.0 with all additions and
  changes
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Mon, 27 Apr 2026 10:50:35 +0200
2d9899ec
feat: add graceful shutdown on SIGINT/SIGTERM/SIGHUP with partial output

- Watch for `SIGINT`, `SIGTERM`, `SIGHUP` in a dedicated goroutine
- Provide `IsExiting()` and `Stop()` for coordinated shutdown
- Unit tests for lifecycle and idempotent stop
- Install signal watcher before any blocking operation
- Cancel context when signal arrives, aborting in‑progress LLM API calls
- On interrupt: write any partial summary received, exit with code 130
- Stop signal watcher in dry‑run, missing‑API‑key, and TUI early exits
- `SummariseArticles()` and `callAPIWithMessages()` accept
  `context.Context`
- Pass context to OpenAI SDK, allowing immediate cancellation on signal
- State field to detect signal‑caused termination (currently unused but
  reserved for future use)
- Remove redundant `lipgloss.NewStyle().Bold(true).Render()` wrappers;
  return plain strings directly
- Delete unused `URL()` function (the styled `URLStyled` remains)
- Update `CHANGELOG.md` with v0.14.0 entry describing signal handling
- Expand `docs/TESTING.md` with sections for `internal/runtime` branch
  tests and `internal/signals` tests
- Add `TestExecuteBranch*` tests for runtime execution paths (stdin
  only, feeds file only, collated, no source)
- Add signal handler tests (`TestSignalHandler_Watch`,
  `TestSignalHandler_IsExiting`, `TestSignalHandler_Stop_Idempotent`)
- Bump `aggregator` package coverage from 33% → 57% via stdin/reader
  parsing tests
- Updated documentation (`llm_aggregator.1`, `llm_aggregator.5`)
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Mon, 27 Apr 2026 10:01:47 +0200
a0e7d1a4
feat: add --stdin flag to read RSS/Atom feed from standard input

- Add `--stdin` flag to read a single RSS/Atom feed directly from stdin
  - Composability with `-f/--feeds-file` to collate articles from both
    sources
  - Stdin articles appear before feeds-file articles in collated output
  - Support environment variable `LLM_AGGREGATOR_STDIN`
- Make `--feeds-file` no longer required; require either `--feeds-file`
  or `--stdin`
- Add `ParseFeedFromReader` and `ParseFeedFromStdin` methods to
  `FeedAggregator`
  - `ParseFeedFromStdin` reads from `os.Stdin`, logs source as "stdin"
  - `ParseFeedFromReader` accepts any `io.Reader` for unit testing
- Refactor `ParseFeedsFromFile` to delegate to a shared
  `parseFeedsFromReader` method
- Update `cmd/llm_aggregator.go` and `internal/runtime/runtime.go` to
  route feed sources
  - Handle three cases: stdin only, feeds file only, both (collated)
  - Return clear error when neither source is provided
- Update `internal/cli/args.go` to make `--feeds-file` optional and add
  `--stdin`
- Extend `internal/config/config.go` to map `stdin` from CLI and
  environment
- Add comprehensive tests:
  - `TestParseFeedFromReader` for RSS and Atom feeds
  - `TestParseFeedFromReaderMalformed` for error handling
  - `TestParseFeedFromStdin` using pipe redirection
- Update documentation:
  - `README.md` with usage examples and environment variable
  - `docs/llm_aggregator.1` with `--stdin` flag and feed input section
  - `CHANGELOG.md` for version 0.13.0
  - Built-in `--help` examples and help sections
- Clean up `go.mod` and `go.sum` by removing unused indirect
  dependencies
  - Remove `charmbracelet/glamour`, `muesli/reflow`, `golang.org/x/term`
    etc.
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Sun, 26 Apr 2026 21:41:51 +0200
af6da634
feat: add --plain flag for raw LLM output without formatting

- Add `-P`/`--plain` CLI flag (`internal/cli/args.go`)
  - Flag suppresses all formatting and metadata, outputting only the LLM
    response
- Implement plain output logic in `internal/runtime/runtime.go`
  - Skip formatter when plain mode is active, write summary directly
- Wire `--plain` through configuration layer
  (`internal/config/config.go`)
  - Map flag to runtime config, bind to `LLM_AGGREGATOR_PLAIN` env var
- Update man page (`docs/llm_aggregator.1`) with new option and
  environment variable
- Add `--plain` to styled help and usage examples
  (`internal/cli/help.go`)
- Extend tests for args-to-viper mapping and config parsing to cover
  plain flag
- Bump version to 0.12.0 and modify `CHANGELOG.md` accordingly
- Bump man page version to 0.12.0 (drive-by)
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Sun, 26 Apr 2026 20:49:14 +0200
e6f50822
test: add CLI help formatting tests and update coverage documentation

- Add `internal/cli/help_test.go` with comprehensive test suite
  - Test `shouldStyle()` for NO_COLOR environment variable handling
  - Test `renderFlag()` for short/long flag formatting
  - Test `getOptionValue()` for type/default value extraction
  - Test `maxFlagWidth()` for column width calculation
  - Test `formatSection()` with and without color styling
  - Test `BuildStyledHelp()` for full help output structure
  - Test `WriteHelp()` for writing help to writer
- Update `docs/TESTING.md` coverage goals with specific percentages
  - Add coverage for `cli` (95%), `config` (82%), `aggregator` (33%),
    etc.
  - Add note about `defaults` and `style` packages (no testable
    statements)
  - Include low-coverage packages (`llm`, `runtime`, `tui`, `progress`,
    `tokeniser`, `cmd`)
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Thu, 23 Apr 2026 18:51:09 +0200
b7690ae4
feat: add accurate token-based progress tracking with pre‑request estimation

- Enhance LLM client to return actual token usage from API response
  - Add `TokenUsage` struct with prompt and completion token counts
  - Update `SummariseArticles` and `callAPIWithMessages` to return
    `(*TokenUsage, error)`
  - Log token usage through progress logger as before
- Add token estimation before API call
  (`contentProc.EstimateTokenCount`)
  - Estimate total prompt tokens using tiktoken with the selected model
  - Pass estimate to progress bar for realistic pre‑request progress
    display
- Extend progress interface with new tracking methods
  - `SetTokenEstimate(total, used int)` for token‑based progress updates
  - `StartWaiting()` to signal the TUI that we are waiting for the LLM
    response
  - Implement no‑op stubs in `SimpleLogger` and `NoopLogger`
- Update TUI (`internal/tui/`) to show token‑based progress
  - Add `TokenEstimateMsg` and `WaitingMsg` channel messages
  - Modify progress bar calculation: use token ratio once estimate is
    available
  - During LLM wait period, show a simulated progress (85‑100% over 60
    seconds)
  - Display "Tokens: used / total" in statistics area
- Revise `README.md` to include an animated demo GIF
  (`./assets/demo.gif`)
- Bump `CHANGELOG.md` with version `0.11.0` entry describing the token
  tracking feature
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Thu, 23 Apr 2026 18:26:54 +0200
b4f6beb3
refactor: remove dead code and simplify API surface

- Remove deprecated constructors and unused functions
  - Delete `NewFeedAggregator` (only `WithProgress` variant remains)
  - Remove `DefaultConfig`, `Load`, `ViperToConfig`, `Save`,
    `ConfigExists` from config
  - Delete `NewRuntime` (runtime now built from config directly)
  - Remove unused formatter helpers (`FormatArticleList`)
  - Delete `AnalyseWithCustomPrompt` from LLM client
  - Drop `CreateConciseContext` and rough‑estimate fallback from
    processor
  - Remove token counting for chat messages (`CountMessagesTokens`,
    `Message` type)
  - Delete TUI command helpers (`Step`, `StepWithCounts`, `Error`)
  - Remove style functions (`Bold`, `Yellow`, `Highlight`,
    `ParseAndStyleURLs`, etc.)
- Add explanatory comments for concurrency limit and content extraction
  heuristics
- Update dependencies (`golang.org/x/net`, `sys`, `term`, `text`) and
  add `golang.org/x/tools/cmd/deadcode` tool directive
- Simplify `aggregator_test.go` to use `NewFeedAggregatorWithProgress`
  exclusively
- Remove obsolete test cases (`TestNewFeedAggregator`,
  `TestDefaultConfig`, `TestConfigLoadWithVariousSources`, etc.)
- Add `NOTE` comments in `config.go` about Viper singleton behaviour and
  `isZero` semantics
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Thu, 23 Apr 2026 15:54:10 +0200
26eb79c0
feat: add short command-line flags and styled help output

- Add single-character shortcuts for all commonly used options
  - `-f` / `--feeds-file` — feeds file path
  - `-p` / `--prompt` — summarisation prompt
  - `-n` / `--max-articles-per-feed` — articles per feed limit
  - `-d` / `--max-days-old` — article age filter
  - `-i` / `--include-keywords` — keyword include filter
  - `-e` / `--exclude-keywords` — keyword exclude filter
  - `-m` / `--model` — LLM model selection
  - `-o` / `--output` — output format
  - `-t` / `--tui` — enable TUI interface
  - `-D` / `--dry-run` — dry run mode
- Replace go-arg's default plain-text help with custom lipgloss-styled
  output
  - Create `internal/cli/help.go` with sectioned, coloured help text
  - Flags rendered in cyan, headers in bold, consistent column alignment
  - Respect `$NO_COLOR` for terminal compatibility
- Update `README.md` to show short flags in option tables and examples
- Update `docs/llm_aggregator.1` man page with short flag documentation
- Update `CHANGELOG.md` for version 0.10.0
- Update `.gitignore` to exclude `AGENTS.md` and `.crush`
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Thu, 23 Apr 2026 14:41:52 +0200
658b2cfd
feat: add markdown rendering and UI refinements to TUI

- Add Markdown rendering using `charmbracelet/glamour`
  - Render LLM summary output with proper styling (headers, bold,
    italic, code blocks, lists)
  - Re-render Markdown dynamically on terminal resize
- Formalise infobar keybinds as dedicated style variables
  - Keybinds bold, separators/actions subtle but distinguishable
- Move thinking toggle indicator to separate line above keybinds
  - Distinct styles: magenta+bold when ON, subtle+italic when OFF
- Implement dynamic text wrapping on terminal resize
  - Summary content re-wraps when window/font size changes
- Update documentation (README, man pages, CHANGELOG)
  - Document Markdown rendering in TUI mode
  - Add glamour to dependency list
  - Bump version to 0.9.0 and document changes in CHANGELOG
- Update dependencies (`go.mod`/`go.sum`)
  - Add `charm.land/glamour/v2`, `github.com/charmbracelet/glamour`
  - Update lipgloss, bubbles, and other charm libraries
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Thu, 23 Apr 2026 12:34:11 +0200
64f25c51
docs: remove TUI preview from README

- Does not really work all that well
- Small correction in `docs/TESTING.md` for "IMPORTANT" callout
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Thu, 23 Apr 2026 11:12:37 +0200
a16b6b07
docs: add TUI preview to README

- Add an SVG animation file to `README.md` for extra gloss
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Thu, 23 Apr 2026 10:54:38 +0200
4316d19f
feat: add thinking tags toggle in TUI for LLM outputs

- Add thinking tag filtering to terminal UI display
  - Automatically remove `<think>...</think>` sections from summary by
default
  - Press `t` to toggle thinking content visibility (displayed in gray
at the head)
  - Add status indicator showing whether thinking is currently visible
(`ON`/`OFF`)
- Update `internal/tui/model.go` with toggle implementation
  - Add `showThinking`, `thinkingContent`, and `cleanSummary` fields to
`Model`
  - Extract thinking content and clean summary in `processingDoneMsg`
using regex
  - Implement `'t'` key handler to regenerate viewport content with or
without thinking
  - Add `wrapTextGray` for gray‑colored text and `stripThinkingTags`
helper
- Update `CHANGELOG.md` with version 0.8.0 entry describing the new
feature
- Fix formatting in `docs/TESTING.md` (remove extraneous line break in
important block)
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Thu, 23 Apr 2026 10:43:45 +0200
51cde19d
fix: prevent unintentional CLI default overrides for config values

- Fix configuration precedence bug where CLI arguments without explicit
  flags were overriding config file and environment variable values
  - Root cause: `go-arg` was populating struct fields with `default:`
    tags even when those CLI flags weren't provided, causing zero values
    to overwrite existing config
  - Remove `default:` tags from Args struct fields for LLM options
    (`model`, `base-url`, `api-key`, `max-tokens`, `temperature`);
    Viper's own default handling now takes precedence
  - Change Args struct fields from value types to pointer types
    (`*string`, `*int`, `*float64`) so that "not provided on CLI" can be
    distinguished from "provided but zero/empty"
- Update `ToViperMap()` to include only non‑nil fields (explicitly
  provided CLI flags), preventing nil pointers from being bound to Viper
- Fix `isZero()` helper to handle nil interface values and pointer types
  correctly, splitting compound type cases into individual checks
- Add comprehensive tests for pointer handling, nil CLI args, and
  explicit zero values (e.g., `--max-tokens 0` should still override
  defaults)
- Update `BindCLIArgs()` to respect the new pointer‑based distinction
- Extend documentation in `docs/TESTING.md` to explain the precedence
  rules and the importance of nil/zero distinction
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Wed, 22 Apr 2026 21:57:41 +0200
715e6710
feat: add --dry-run mode and styled terminal output with NO_COLOR support

- Add `--dry-run` CLI flag to validate configuration and preview
  articles without making LLM API calls
  - Show feeds file validation, configuration summary, article
    statistics
  - Display filtered article counts, source breakdown, token estimates
  - Skip API key validation when `--dry-run` is active
- Implement styled terminal output using `lipgloss`
  - Add `internal/style` package with ANSI colour helpers
  - Style errors, warnings, success messages, labels, filepaths, URLs
  - Respect `$NO_COLOR` environment variable (no-color.org standard)
- Update `cmd/llm_aggregator.go` to support dry-run execution
  - Add `runDryRun()` function that fetches and processes feeds without
    LLM
  - Move API key validation after dry-run check
  - Replace raw `fmt.Fprintf` errors with styled error output
- Revise `internal/progress/progress.go` to use styled warnings and
  debug
- Refactor `internal/llm/llm.go` client creation to use option slice
- Improve `configs/config.example.toml` with inline comments for all
  options
- Add project logo (`assets/logo.svg`) to README
- Update `README.md` and `docs/llm_aggregator.1` with `--dry-run` docs
- Extend `internal/cli/args_test.go` with dry-run flag test cases
- Update `CHANGELOG.md` for version 0.7.0
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Wed, 22 Apr 2026 20:38:55 +0200
97ccb8da
docs: improve README readability with tables for env vars and dependencies

- Convert environment variables list to markdown table for cleaner
  layout
- Convert dependencies list to markdown table with descriptions
- Move `TESTING.md` reference from bottom to appropriate "How do I
  build" section
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Wed, 22 Apr 2026 15:18:24 +0200
4606d779
docs: add man pages for llm_aggregator

- Add `docs/llm_aggregator.1` (user command man page)
  - Document all command-line options (feed aggregation, content
    filtering, LLM API, output formats, TUI interface)
  - Include environment variables, configuration precedence, examples,
    exit status, and dependencies
- Add `docs/llm_aggregator.5` (configuration file man page)
  - Describe TOML config file structure with sections for
    feed_aggregation, filtering, llm_api, system, and output
  - Provide full example configuration and security considerations
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Wed, 22 Apr 2026 15:12:45 +0200
7a6aa2c8
feat: add comprehensive test suite, --base-url option, and central defaults package

- Add comprehensive unit test suite across all major packages
  - `internal/cli/args_test.go`: CLI argument tests for all flags
  - `internal/aggregator/aggregator_test.go` and `article_test.go`: feed
    parsing, filtering, sorting
  - `internal/output/formatter_test.go`: JSON, Markdown, and text output
    formatting
  - `internal/processor/processor_test.go`: article processing, keyword
    filtering, sorting
  - `internal/config/config_test.go`: configuration loading and Viper
    integration
  - `internal/defaults/defaults_test.go`: default constants validation
- Add `--base-url` CLI option to configure custom LLM API endpoints
  - Support any OpenAI-compatible provider (e.g., local Ollama, Azure
    OpenAI)
  - Environment variable: `LLM_AGGREGATOR_BASE_URL`
  - Default: `https://api.deepseek.com`
- Add `internal/defaults` package to centralise all default constants
  - `internal/config`, `internal/runtime`, `internal/llm` now use
    `defaults.Default*`
  - Eliminates hard-coded default values scattered across packages
- Add `docs/TESTING.md` with comprehensive testing guide
  - Explains test structure, helper functions, and coverage goals
  - Includes examples of table-driven tests and nil safety testing
- Fix nil pointer safety in `internal/aggregator`
  - Add nil checks for `progressCtx` before each log/warning/debug call
  - `FeedAggregator` now works correctly when progress context is nil
  - Tests explicitly use `NewFeedAggregatorWithProgress` with proper
    context
- Update `README.md` to document `--base-url` flag and environment
  variable
- Update `CHANGELOG.md` with version 0.6.0 changes
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Wed, 22 Apr 2026 14:54:49 +0200
262b9113
feat: add accurate token counting, concurrent feed fetching, and scrollable TUI summary

- Add accurate token counting with tiktoken
  - New `internal/tokeniser` package using
    `github.com/pkoukk/tiktoken-go`
  - BPE tokenisation for precise counting vs rough character estimation
  - Encoding caching and model-aware encoding selection (cl100k_base,
    o200k_base, etc.)
  - `CountTokens()` and `CountMessagesTokens()` functions
  - Fallback to rough estimation when tiktoken initialisation fails
- Add concurrent feed fetching with errgroup
  - Fetch feeds in parallel using `golang.org/x/sync/errgroup`
  - Semaphore limits concurrent requests to 10 to avoid server overload
  - Mutex-protected shared state for thread-safe article collection
  - Partial feed failures do not stop other feeds from being processed
- Add scrollable summary view in TUI
  - Integrate `bubbles/viewport` component for browsing long summaries
  - Keyboard navigation: j/k or arrows (scroll), Space/B (page), g/G
    (start/end)
  - Mouse wheel scrolling support
  - Scroll progress indicator showing position and total lines
- Streamline configuration management
  - Use global Viper instance with automatic precedence handling
  - Simplify configuration flow: Parse → GetViper → BindCLIArgs →
    ViperToRuntime
  - Remove manual precedence logic from `cmd/llm_aggregator.go`
- Replace TUI hex colour codes with ANSI 256-colour palette
- Fix viewport scroll event handling and content pre-wrapping before
  display
- Rename `internal/llm/deepseek.go` to `internal/llm/llm.go` (generalise
  LLM client)
- Update `CHANGELOG.md` (v0.5.0) and `README.md` to document new
  features
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Wed, 22 Apr 2026 10:46:14 +0200
9193c5f1
refactor: generalise Deepseek-specific naming to generic LLM

- Rename `DeepseekClient` to `LLMClient` in `internal/llm/deepseek.go`
  - Update constructor `NewDeepseekClient` → `NewLLMClient`
  - Change all comments and log messages from "Deepseek" to "LLM"
- Update `internal/runtime/runtime.go` to use `NewLLMClient` instead
- Replace all references to "Deepseek API" with "LLM API" across:
  - `README.md` – section headings, environment variables, examples
  - `configs/config.example.toml` – comments and section titles
  - `internal/cli/args.go` – flag help text, description, environment
    note
  - `internal/config/config.go` – struct comments and bindEnv calls
- Keep default model as `deepseek-chat` and base URL as
  `https://api.deepseek.com`
  - The client remains compatible with Deepseek but clearly supports any
    OpenAI‑compatible LLM provider
- Improve error messages to be provider‑agnostic (e.g., "invalid API
  key" without mentioning Deepseek)
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Wed, 22 Apr 2026 09:33:31 +0200
7208dd81
fix: restructure TUI with bubbletea command pattern and progress interface

- Replace manual goroutine and signal handling with native bubbletea
  commands
  - Move runtime execution into `Model.startProcessing()` tea.Cmd
  - Remove `runWithTUI` goroutine orchestration and channel
    synchronisation
- Introduce `progress.Progress` interface and inject into
  `runtime.Runtime`
  - Add `SetStage`, `SetSubStage`, `SetArticleCount` methods to
    `SimpleLogger` and `NoopLogger`
  - Replace internal `logger *progress.Context` with `Progress
    progress.Progress` field
- Simplify `TUIProgress` to only send messages to existing `tea.Program`
  - Remove program creation and runtime execution from `TUIProgress`
  - Use `StageMsg`, `SubStageMsg`, `ArticleCountMsg` for updates
- Update `Model` to hold `*runtime.Runtime` and display spinner
  - Add `spinner` model and tick command for visual feedback
  - Show checkmark on completion, capture elapsed time, and display
    summary inline
- Clean up unused `StepMsg` related functions and redundant blank lines
- Adjust `applyConfiguration` formatting and remove unused imports
  (`os/signal`, `syscall`)
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Tue, 21 Apr 2026 21:47:59 +0200
6e3abd06
feat: add configuration file and environment variable support

- Add `internal/config` package with Viper-based TOML loading
  - Load configuration from `~/.config/llm_aggregator/config.toml` (XDG
    compliant)
  - Support all aggregation, API, and output options in config file
  - Implement precedence: CLI args > env vars > config file > built‑in
    defaults
- Integrate config loading into `cmd/llm_aggregator.go`
  - Call `config.Load()` before argument parsing
  - Apply config values to runtime with `applyConfiguration()`
  - Gracefully warn if config file exists but fails to load
- Rename environment variable prefix from `DEEPSEEK_API_KEY` to
  `LLM_AGGREGATOR_API_KEY`
  - Update `internal/cli/args.go` help text and environment variable
    reference
  - Update `internal/llm/deepseek.go` to read `LLM_AGGREGATOR_API_KEY`
  - Update `README.md` and `CHANGELOG.md` to reflect new variable name
- Add `configs/config.example.toml` with documented configuration
  options
- Add `internal/config/config_test.go` covering defaults, path
  resolution, save/load, and environment variable precedence
- Update `go.mod` / `go.sum` with new dependencies:
  - `github.com/spf13/viper` for configuration management
  - `github.com/adrg/xdg` for XDG base directory support
  - `github.com/pelletier/go-toml/v2` (indirect via viper)
- Revise `README.md` to document the new configuration system,
  precedence order, and environment variables
- Update `CHANGELOG.md` for version 0.3.0
- Remove unused `internal/config` global flags (`QuietMode`,
  `VerboseMode`) replaced by runtime configuration
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Tue, 21 Apr 2026 18:37:19 +0200
13547fc8
feat: add verbose flag to control progress and status messages

- Make CLI silent by default; only final output and errors are displayed
  - Move all progress logs, warnings, and debug messages behind
    `-v/--verbose`
- Introduce logger interface (`progress.Context`) for consistent logging
  - Add `NoopLogger` for silent mode, `SimpleLogger` for verbose output
- Update components to use logger instead of direct `fmt.Print` calls
  - `aggregator.FeedAggregator` accepts logger via
    `NewFeedAggregatorWithProgress`
  - `processor.ContentProcessor` gains `SetLogger` method
  - `llm.DeepseekClient` gains `SetLogger` method
- Modify `runtime.Runtime` to create appropriate logger from `Verbose`
  flag
- Update CLI flag description: `--verbose` now says "Show verbose
  output"
- Remove redundant conditional logging blocks (if verbose) from
  `cmd/llm_aggregator.go`
- Ensure token estimates, filtering summaries, and API call logs only
  appear in verbose mode
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Tue, 21 Apr 2026 15:41:41 +0200
7b6943f1
feat: initial implementation of LLM RSS aggregator with DeepSeek summarisation

- Add core aggregation engine (`internal/aggregator/`)
  - Parse RSS/Atom/JSON feeds using `gofeed`
  - Extract article metadata (title, link, date, author)
  - Fallback to web scraping with `goquery` for minimal content
- Add content processing and filtering (`internal/processor/`)
  - Keyword-based include/exclude filtering
  - Sort by date, title, or source
  - Token estimation and context preparation
- Add DeepSeek API integration (`internal/llm/`)
  - OpenAI-compatible client for chat completions
  - Configurable model, max tokens, temperature
  - Support custom system prompts
- Add command-line interface (`internal/cli/`)
  - `go-arg` based argument parsing
  - Options for feeds file, prompt, filtering, output formats
  - Environment variable support for API key
- Add output formatting (`internal/output/`)
  - Plain text, GitHub‑flavoured markdown, and JSON outputs
  - Optional inclusion of original articles
- Add terminal user interface (`internal/tui/`)
  - Bubble Tea based progress bar with gradient colours
  - Live article counters and elapsed time
  - Keyboard controls (q/Ctrl+C to quit)
- Add runtime orchestration (`internal/runtime/`)
  - Pipeline execution (aggregate → process → summarise → output)
  - File output support
- Add project documentation
  - `README.md` with usage examples and dependencies
  - `CHANGELOG.md` for version 0.1.0
  - `LICENCE.txt` (EUPL 1.2)
  - Third‑party library READMEs in `docs/` for reference
- Add build configuration
  - `go.mod` with dependencies (gofeed, openai-go, bubbletea, lipgloss,
    go-arg, goquery)
  - `.goreleaser.yaml` for cross‑platform releases
  - `.gitignore` for Go binaries and test artifacts
Maxwell Jensen 85795372+maxwelljens@users.noreply.github.com
Tue, 21 Apr 2026 14:44:42 +0200