Skip to content

A scriptable terminal cli (great for AI agents too)

License

Notifications You must be signed in to change notification settings

intelligrit/feed-cli

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

feed-cli

An Intelligrit Labs Project

feed-cli logo

A minimal, scriptable RSS/Atom feed reader for the command line. Designed for automation, scripting, and AI systems with JSON-first output.

Features

  • Scriptable - JSON output by default, perfect for piping to jq or other tools
  • Fast - CGo-free SQLite for easy cross-compilation
  • Pagination - Full --offset and --limit support
  • Date filtering - Simple --since 7d syntax
  • Read tracking - Mark entries as read/unread
  • Categories - Organize feeds by category
  • TDD - Comprehensive test coverage

Installation

go install github.com/intelligrit/feed-cli/cmd/feed-cli@latest

Or build from source:

git clone https://github.com/intelligrit/feed-cli
cd feed-cli
make build
# Binary will be in bin/feed-cli

Quick Start

# Add a feed
feed-cli add https://news.ycombinator.com/rss --category tech

# List all feeds
feed-cli feeds | jq '.'

# Update feeds (fetch new entries)
feed-cli update

# List latest entries
feed-cli list --limit 10 | jq '.entries[].title'

# List unread entries from last week
feed-cli list --unread --since 7d | jq '.'

Usage

Feed Management

# Add a feed
feed-cli add <url> [--category <category>]

# List all feeds
feed-cli feeds

# Update all feeds
feed-cli update

# Update specific feed
feed-cli update --feed-id 1

# Remove a feed
feed-cli remove <feed-id>

Browsing Entries

# List entries with pagination
feed-cli list --limit 20 --offset 0

# Show only unread entries
feed-cli list --unread

# Filter by date (7 days, 2 weeks, 3 months, 1 year)
feed-cli list --since 7d
feed-cli list --since 2w
feed-cli list --since 3m
feed-cli list --since 1y

# Combine filters
feed-cli list --unread --since 2w --limit 50

# Show full entry details
feed-cli show <entry-id>

Read Tracking

# Mark entries as read
feed-cli mark-read <entry-id> [<entry-id>...]

# Mark all entries as read
feed-cli mark-all-read

Database Location

By default, the database is stored at ~/.config/feed-cli/feed-cli.db.

Override with:

  • --db flag: feed-cli --db /path/to/db.db list
  • FEED_CLI_DB environment variable

JSON Output & jq Examples

All commands output JSON by default, making feed-cli perfect for scripting.

Pretty Print

# Pretty print all feeds
feed-cli feeds | jq '.'

# Pretty print entries
feed-cli list | jq '.'

Extracting Data

# Get all feed titles
feed-cli feeds | jq -r '.[].title'

# Get all feed URLs
feed-cli feeds | jq -r '.[].url'

# Count unread entries
feed-cli list --unread | jq '.count'

# Extract entry URLs
feed-cli list --since 7d | jq -r '.entries[].link'

# Get titles of unread entries
feed-cli list --unread | jq -r '.entries[].title'

# Get entry titles and links as table
feed-cli list --limit 5 | jq -r '.entries[] | "\(.title)\t\(.link)"'

Filtering with jq

# Find entries with "golang" in title
feed-cli list | jq '.entries[] | select(.title | test("golang"; "i"))'

# Get entries from a specific feed ID
feed-cli list | jq '.entries[] | select(.feed_id == 1)'

# Count entries per feed
feed-cli list | jq '[.entries[] | .feed_id] | group_by(.) | map({feed_id: .[0], count: length})'

Opening in Browser

# Open first 5 unread entries in browser
feed-cli list --unread --limit 5 | jq -r '.entries[].link' | xargs -n1 open

# Open specific entry
feed-cli show 123 | jq -r '.link' | xargs open

Scripting Examples

Daily digest script:

#!/bin/bash
# daily-digest.sh - Email yourself unread entries

UNREAD=$(feed-cli list --unread --since 1d | jq -r '.entries[] | "- \(.title): \(.link)"')

if [ -n "$UNREAD" ]; then
    echo "$UNREAD" | mail -s "Daily Feed Digest" you@example.com
    feed-cli mark-all-read
fi

Feed stats:

#!/bin/bash
# feed-stats.sh - Show feed statistics

echo "=== Feed Statistics ==="
echo "Total feeds: $(feed-cli feeds | jq 'length')"
echo "Total entries: $(feed-cli list --limit 999999 | jq '.count')"
echo "Unread entries: $(feed-cli list --unread | jq '.count')"
echo ""
echo "=== Top Feeds ==="
feed-cli list | jq -r '[.entries[] | .feed_id] | group_by(.) | map({feed_id: .[0], count: length}) | sort_by(.count) | reverse | .[:5][] | "\(.count) entries from feed \(.feed_id)"'

Import from feeds.yaml:

#!/bin/bash
# import-feeds.sh - Import feeds from YAML file

yq eval '.feeds[].url' feeds.yaml | while read url; do
    category=$(yq eval ".feeds[] | select(.url == \"$url\") | .category" feeds.yaml)
    feed-cli add "$url" --category "$category"
done

Examples

Workflow Example

# Morning routine: Check and read feeds

# 1. Update all feeds
feed-cli update

# 2. See what's new
feed-cli list --unread --since 1d | jq -r '.entries[] | "\(.title)"'

# 3. Open interesting articles
feed-cli list --unread --limit 5 | jq -r '.entries[].link' | xargs -n1 open

# 4. Mark as read
feed-cli mark-all-read

Integration with Other Tools

# Export to CSV
feed-cli list | jq -r '.entries[] | [.id, .title, .link, .published] | @csv' > entries.csv

# Filter with fzf
feed-cli list | jq -r '.entries[] | "\(.id)\t\(.title)"' | fzf | cut -f1 | xargs feed-cli show

# Send to Slack webhook
feed-cli list --unread --limit 3 | jq '.entries[] | {text: .title, url: .link}' | \
  xargs -I{} curl -X POST -H 'Content-type: application/json' --data '{}' YOUR_WEBHOOK_URL

Development

Building

make build          # Build binary
make test           # Run all tests
make test-unit      # Run unit tests only
make test-coverage  # Generate coverage report
make lint           # Run linter
make clean          # Clean build artifacts

Testing

feed-cli follows Test-Driven Development (TDD):

# Run all tests
go test ./...

# Run specific package tests
go test ./model -v
go test ./store -v
go test ./feed -v

# Run with coverage
go test -cover ./...

Project Structure

feed-cli/
├── cmd/feed-cli/    # CLI entry point
├── model/           # Data structures
├── store/           # SQLite database operations
├── feed/            # RSS/Atom fetching
├── opml/            # OPML import/export (future)
└── testdata/        # Test fixtures

Architecture

feed-cli uses a simple, flat package structure:

  • model/ - Core data types (Feed, Entry, Tag)
  • store/ - SQLite database layer with query builder
  • feed/ - RSS/Atom parser (wraps gofeed)
  • cmd/feed-cli/ - CLI commands and JSON output

No complex abstractions, just clean separation of concerns.

Dependencies

  • gofeed - RSS/Atom parsing
  • modernc.org/sqlite - CGo-free SQLite
  • urfave/cli/v2 - CLI framework
  • testify - Testing assertions

Database Schema

Simple relational schema with proper indexes:

feeds
  ├─ id, url (unique), title, category
  └─ etag, last_modified (for HTTP caching)

entries
  ├─ id, feed_id (FK), guid, title, link
  ├─ content, published, is_read
  └─ UNIQUE(feed_id, guid) -- prevent duplicates

tags (future)
  └─ id, name

entry_tags (future)
  └─ entry_id (FK), tag_id (FK)

Roadmap

  • Core feed management
  • Read/unread tracking
  • Pagination
  • Date filtering
  • JSON output
  • OPML import/export
  • Tag support
  • Full-text search
  • Web interface (optional)
  • HTTP caching (ETags, Last-Modified)

About Intelligrit Labs

feed-cli is developed by Intelligrit Labs, the R&D arm of Intelligrit LLC. We build tools for ourselves and release them for everyone. Intelligrit delivers AI-driven IT modernization for federal agencies.

License

MIT License - see LICENSE file

Contributing

Pull requests welcome! Please:

  1. Write tests for new features
  2. Follow existing code style
  3. Update README if adding commands

Credits

Built with:

About

A scriptable terminal cli (great for AI agents too)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published