logs.gokuls.in

9 pull requests merged across 4 repos

bahdotsh/blogr

Adds support for external posts — posts that appear in all blog listings but link to an external URL instead of having local content. This lets blog authors curate articles they've published on other sites.

Closes #35

  • Adds optional external_url field to PostMetadata (backward-compatible via #[serde(default)])
  • External posts appear in index, archive, tag pages, RSS/Atom feeds, search index, and JSON API — but no local .html page is generated
  • All 4 blog themes (brutja, terminal_candy, minimal_retro, obsidian) and their simple variants updated with indicator and target="_blank"
  • CLI: blogr new "Title" --external-url "https://..." creates an external post

Example frontmatter

---
title: "My Article on Another Blog"
date: "2026-03-31"
author: "Author"
description: "An article published elsewhere"
tags: ["rust"]
status: "published"
slug: "my-article-on-another-blog"
external_url: "https://example.com/article"
---

Test plan

  • cargo build — compiles cleanly
  • cargo test — all 123 tests pass (including 2 new external post tests)
  • cargo clippy --all-targets --all-features -- -D warnings — zero warnings
  • cargo fmt --all -- --check — formatting clean
  • Manual: blogr new "External" --external-url "https://example.com" creates external post with empty content
  • Manual: blogr build generates site with external post in listings, no posts/external.html generated
  • Manual: RSS/Atom feeds contain external URL for external posts
  • Fixes search result excerpts showing sentences mashed together without spaces where paragraph/block boundaries existed in the original markdown
  • Adds space insertion for End(Paragraph), End(Heading), End(Item), and End(BlockQuote) events in markdown_to_text()
  • Downstream extract_excerpt() already collapses whitespace via split_whitespace().join(), so extra spaces are harmless

Fixes #25

Test plan

  • cargo test -p blogr-cli — all 113 tests pass
  • cargo clippy --all-targets --all-features -- -D warnings — clean
  • Build a site with multi-paragraph posts and verify search_index.json excerpts have proper spacing

bahdotsh/feedr

  • Module split: Decomposed ui.rs (2872 lines) into 10 modules under src/ui/ and extracted events.rs from tui.rs for maintainability
  • 8 new features spanning high-impact usability and quality-of-life improvements:
  • ? Help overlay: scrollable keybinding cheatsheet, context-aware per view
  • m Mark all as read: bulk mark scoped to dashboard, feed, category, or starred
  • Feed tree view: FeedList is now a collapsible category tree with folder nodes
  • Mouse support: scroll wheel for lists/content, click to dismiss overlays
  • l Link extraction: parse article HTML for links/images, open from overlay
  • Global search: / now available from all views (was missing in Starred, Detail)
  • Per-feed refresh: refresh_interval per feed in config.toml
  • Configurable keybindings: [keybindings] config section with KeyAction enum, key_matches() helper, and 11 unit tests

Details

Module refactor

BeforeAfter
ui.rs (2872 lines)src/ui/ with 10 modules (mod, dashboard, feed_list, feed_items, detail, starred, summary, categories, modals, utils)
tui.rs (1226 lines)tui.rs (190 lines) + events.rs (1100+ lines)

Configurable keybindings example

[keybindings]
quit = "x"
move_up = ["w", "Up"]
toggle_star = "Ctrl+s"
open_search = "Ctrl+f"

Feed tree view

▾ Tech (3 feeds)
    ◆ Hacker News (25)
    ◆ TechCrunch (12)
▸ News (2 feeds)
  ◆ Reddit /r/rust (15)

Test plan

  • cargo fmt --all -- --check passes
  • cargo clippy --all-targets --all-features -- -D warnings passes
  • cargo test --all-features --verbose — 45 tests pass (41 unit + 4 integration)
  • Manual smoke test: press ? from each view, scroll, dismiss
  • Manual: press m in Dashboard/FeedItems/FeedList, verify items marked read
  • Manual: press l in article detail, verify links listed, open with Enter
  • Manual: scroll wheel in lists, verify navigation
  • Manual: assign feeds to categories, verify tree rendering, expand/collapse
  • Manual: add [keybindings] overrides to config.toml, verify remapped keys work
  • Manual: add refresh_interval = 60 to a feed, verify independent refresh

When a user adds a regular web page URL instead of a direct feed URL, feedr now auto-discovers RSS/Atom feed links from <link rel="alternate"> elements in the HTML:

  • Single feed found: automatically adds it
  • Multiple feeds found: shows a selection modal for the user to pick
  • No feeds found: shows a clear error message instead of the old cryptic "received HTML" error

Changes

  • feed.rs: Added DiscoveredFeed struct, HtmlWithFeedsError custom error type, and discover_feeds_from_html() function using the scraper crate. Modified HTML detection to return discovered feeds instead of a generic error.
  • app.rs: Added SelectDiscoveredFeed input mode and discovery state fields.
  • tui.rs: Modified InsertUrl handler to downcast HtmlWithFeedsError and branch on feed count. Added SelectDiscoveredFeed input handler (j/k nav, Enter select, Esc cancel).
  • ui.rs: Added themed render_feed_selection_modal() with [RSS]/[Atom] badges, titles, URLs, and highlighted selection.
  • Cargo.toml: Added scraper and url dependencies.

Test plan

  • cargo clippy --all-targets --all-features -- -D warnings passes
  • cargo test --verbose passes (8 new unit tests for discovery logic)
  • Manual test: run feedr, press a, enter a blog URL (e.g. https://blog.rust-lang.org/), verify feed auto-discovery works
  • Manual test: enter a URL with multiple feeds, verify selection modal appears
  • Manual test: enter a URL with no feeds, verify clear error message

— category switching on the dashboard was broken because event handlers and rendering used different item lists.

  • Rendering correctly used filtered_dashboard_items when a category filter was active, but all interactions (navigation, Enter, Star, Space) indexed into the unfiltered dashboard_items — so pressing Enter on item 3 in a filtered view opened a completely different article
  • selected_item was never clamped after apply_filters() shrank the visible list, so the cursor could point past the end of filtered results
  • Added active_dashboard_items() as a single source of truth for the currently visible item list, used consistently in both ui.rs (rendering) and tui.rs (event handling)
  • Added clamp_dashboard_selection() called at the end of apply_filters() to keep selection valid

Files changed

FileWhat
src/app.rsAdded active_dashboard_items(), active_dashboard_item(), clamp_dashboard_selection()
src/tui.rsUpdated Star, Up, Down, Enter, Space handlers to use active_dashboard_items()
src/ui.rsReplaced inline list selection and dashboard_item(idx) with shared helpers

Test plan

  • cargo clippy --all-targets --all-features -- -D warnings — clean
  • cargo test --all-features --verbose — all 22 tests pass
  • Manual: run app, add feeds to multiple categories, cycle c through categories — verify correct items shown, Enter opens the right article, star/space work on the visible item, selection doesn't jump out of bounds
  • Manual: verify refresh (r) with an active category filter doesn't cause items to flash and disappear

bahdotsh/indxr

  • find(mode: "callers") and summarize(glob) compound tools now return compact columnar {columns, rows} format by default, matching how symbol/signature/relevant modes already worked
  • Adds compact boolean param to granular get_callers and batch_file_summaries tool schemas for direct usage
  • Normalizes import refs in get_callers compact output (sets name from import text, kind to "import") for uniform column layout

Test plan

  • cargo build — compiles cleanly
  • cargo test — all 354 tests pass
  • Manual MCP test: call find(query, mode: "callers") and verify compact columnar response
  • Manual MCP test: call summarize("src/**/*.rs") and verify compact columnar response
  • Replace 12 granular default MCP tools with 3 compound tools (find, summarize, read) that dispatch to existing implementations — reduces per-round schema overhead from ~1,100 to ~422 tokens
  • Inject codebase tree context into benchmark agent prompt, simulating real INDEX.md usage
  • Rewrite benchmark questions as realistic developer tasks (43 questions across navigate/understand/design)
  • Track schema vs content token overhead separately

Compound tools

ToolSchemaReplaces
find(query, mode?)~122 toksearch_relevant, lookup_symbol, get_callers, search_signatures, explain_symbol
summarize(path, scope?)~135 tokget_file_summary, get_public_api, batch_file_summaries, explain_symbol, list_declarations, get_file_context
read(path, symbol?, ...)~164 tokread_source

All 23 granular tools remain callable via --all-tools (26 total). No breaking changes — granular tools still work, just not listed by default.

Why this matters

Tool definitions are re-sent by the API on every round. This is a universal tax paid by every MCP client (Claude Code, Cursor, Windsurf). 3 tools instead of 12+ means ~750 fewer tokens per round across every conversation for every user. Combined with context injection and simpler tool selection (fewer rounds), projected ~5x total token reduction.

Test plan

  • cargo test — 329 tests pass
  • cargo clippy — no new warnings
  • python -m bench --dry-run — 3 tools loaded, tree context injected
  • python -m bench --runs 1 — full benchmark run to validate token reduction

bahdotsh/wrkflw

  • Parse and support the GitHub Actions container directive at the job level, handling both string (container: node:18) and object (container: { image: ..., env: ..., volumes: ... }) formats
  • Use the container image as the runner image when specified, with runs-on as fallback
  • Propagate container env vars (lowest precedence), mount container-defined volumes, and remap GitHub env file paths inside container runtimes
  • Extract shared volume/env-remapping logic into prepare_container_mounts() helper to avoid duplication across Docker-action and run-step branches
  • Handle single-path volume specs (/data) by mounting at the same path inside the container
  • Warn when unsupported container fields (options, credentials, ports) are specified

Closes #58

Test plan

  • Parser tests for deserialize_container: string format, full object format, absent container, registry image with colon in tag
  • All existing tests pass (114 total)
  • cargo clippy clean
  • cargo fmt clean
  • New action_resolver module fetches action.yml / action.yaml from raw.githubusercontent.com for third-party actions and parses runs.using to determine the action type (Node/Docker/Composite)
  • prepare_action() now tries remote resolution first, selecting the correct Docker image based on the action's metadata, and falls back to the existing hardcoded mapping on any failure (zero regressions)
  • Remote composite actions are now supported — cloned into a tempdir and executed via the existing execute_composite_action() path
  • ActionInfo.version field added so the @ref portion of action references is preserved for fetching the correct version
  • Supports GITHUB_TOKEN env var for private repos; results are cached in memory with negative caching

Test plan

  • All 83 existing tests pass
  • 8 new unit tests for action.yml parsing (Node, Docker, Composite, missing runs, image mapping)
  • cargo clippy — no new warnings
  • cargo fmt — clean
  • Manual test with a workflow using EmbarkStudios/cargo-deny-action or similar third-party action
  • Manual test with a well-known action (e.g., actions/checkout) to confirm no regression