{"id":46118759,"url":"https://github.com/kantord/blogtato","last_synced_at":"2026-04-04T13:18:34.365Z","repository":{"id":339832361,"uuid":"1163532080","full_name":"kantord/blogtato","owner":"kantord","description":"A CLI RSS/Atom feed reader inspired by Taskwarrior","archived":false,"fork":false,"pushed_at":"2026-03-07T16:49:48.000Z","size":28888,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-07T17:46:00.711Z","etag":null,"topics":["atom-feed-reader","cli","rss","rss-reader","suckless","taskwarrior"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kantord.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-21T19:18:37.000Z","updated_at":"2026-03-07T15:33:46.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/kantord/blogtato","commit_stats":null,"previous_names":["kantord/rss","kantord/blogwarrior"],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/kantord/blogtato","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kantord%2Fblogtato","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kantord%2Fblogtato/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kantord%2Fblogtato/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kantord%2Fblogtato/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kantord","download_url":"https://codeload.github.com/kantord/blogtato/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kantord%2Fblogtato/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30478929,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-13T20:45:58.186Z","status":"ssl_error","status_checked_at":"2026-03-13T20:45:20.133Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["atom-feed-reader","cli","rss","rss-reader","suckless","taskwarrior"],"created_at":"2026-03-02T00:01:28.853Z","updated_at":"2026-04-04T13:18:34.325Z","avatar_url":"https://github.com/kantord.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# blogtato\n\nA CLI RSS/Atom feed reader inspired by Taskwarrior.\n\n![demo](demo/demo.gif)\n\n## Features\n\n- Subscribe to RSS and Atom feeds\n- Simple query language for filtering by feed, read status, and date, with\n  grouping and export\n- Git-based sync across machines with conflict-free merge\n  ([why git?](#design-philosophy))\n- No accounts, no servers, no continuous network dependency\n- Mark content as read\n- Designed to be distraction free, minimalistic and work out of the box\n\n## Install\n\n```bash\ncargo install blogtato\n```\n\n### Git sync\n\n`git` based synchronization is entire optional. `blogtato` can work entirely\noffline on a single device.\n\nTo set up git synchronization, create a private repo on your git host, then:\n\n```bash\n# On your first machine\nblog clone user/repo\n\n# From now on, sync fetches feeds and pushes/pulls from the remote\n# with no remote repository, `blog sync` just pulls the latest posts from\n# all feeds\nblog sync\n```\n\nOn your device(s), run the same `blog clone` to pull down your feeds and posts.\n\nDon't worry about setting git sync up if you are just trying `blogtato` out:\nyou can run `blog clone user/repo` later and your existing feeds will be merged\nwith the remote automatically.\n\n### Quick start\n\nOnce you set up your `git`-based sync, or if you decided to skip it, subscribe\nto your favorite feeds using `blog feed add`:\n\n```bash\nblog feed add https://michael.stapelberg.ch\nblog feed add https://www.justinmklam.com\n```\n\nYou can import your subscriptions from other RSS readers\n([Feedly](https://docs.feedly.com/article/52-how-can-i-export-my-sources-and-feeds-through-opml),\n[Inoreader](https://www.inoreader.com/blog/2014/05/opml-subscriptions.html),\n[NetNewsWire](https://netnewswire.com/help/mac/5.0/en/export-opml.html),\n[FreshRSS](https://freshrss.github.io/FreshRSS/en/developers/OPML.html),\n[Feeder](https://news.nononsenseapps.com/posts/2.5.0_opml/),\n[Tiny Tiny RSS](https://tt-rss.org/docs/Installation-Guide.html#opml),\n[Outlook](https://support.microsoft.com/en-us/office/share-or-export-rss-feeds-5b514f38-8671-447c-8c25-7f02cc0833e0),\nand others) using an OPML file:\n\n```bash\nblog feed import feeds.opml\n```\n\nFetch and list latest posts:\n\n```bash\nblog sync\nblog\n```\n\nRead whatever you found interesting by referring to its shorthand\n\n```bash\nblog df read\n```\n\nYou can subscribe to `blogtato` releases to know when new features or fixes are\navailable:\n\n```bash\nblog feed add https://github.com/kantord/blogtato/releases.atom\n```\n\n## Usage examples\n\n```bash\n# Subscribe to a feed\nblog feed add https://news.ycombinator.com/rss\n\n# Fetch new posts and sync with git remote\nblog sync\n\n# Show posts (defaults to unread posts from the last 3 months, grouped by week)\nblog\n\n# Group by date, week, or feed\nblog /d\nblog /w\nblog /f\n\n# Combine groupings\nblog /d /f\n\n# Filter by feed shorthand\nblog @hn\n\n# Filter by read status\nblog .unread\nblog .read\nblog .all\n\n# Filter by date\nblog 1w..\nblog 3m..1m\nblog /d 2w..1w\n\n# Combine filters - list unread posts form HackerNews grouped by date\nblog @hn .unread /d\n\n# Open a post in the default browser\nblog abc open\n\n# Print a post URL (useful with CLI browsers)\nblog abc read\nw3m $(blog abc read)\n\n# Mark a post as unread\nblog abc unread\n\n# Export matching posts as JSONL\nblog .all export\nblog @myblog export\nblog 1w.. export\n\n# List subscriptions\nblog feed ls\n\n# Remove a feed\nblog feed rm https://news.ycombinator.com/rss\nblog feed rm @hn\n```\n\n## Design philosophy\n\nI built `blogtato` around the idea of subscription detox and simplicity. I just\nwanted to use a simple and RSS reader that is not distracting, but can be\nsynced between different devices seamlessly without having to set up another\nuser account and paying another monthly subscription fee.\n\n`blogtato` uses a simple database that stores data in JSONL files and syncs\nthem using `git`. From a performance standpoint, this is admittedly\nsub-optimal, and an quite esoteric design. At the same time, if you are\ncomfortable with CLI tools you likely have access to a remote `git` host such\nas GitHub, GitLab or a Forgejo instance: and that's all `blogtato` needs to be\nable to keep data up to date on all of your devices. From a user perspective,\nthis just works with effectively zero configuration.\n\n`blogtato`'s database uses a conflict-free design: even if you have diverging\nchanges between different devices, you will never have to manually resolve\nconflicts. You can forget about `git` being there.\n\nNetwork operations are always initiated by the user. There is no need for a\ncontinuously running server. And all operations that don't strictly need\nnetwork access work offline.\n\nIt is my goal to keep the feature-set and the complexity of this project down,\nso that it can be maintained with minimal effort and can be considered to be\n\"done\".\n\n## Optional configuration\n\n**`blogtato` is designed to work out of the box without any configuration.**\nMost users should never need to change any settings. Nevertheless, a few things\ncan be configured, when the nature of the synchronized database calls for\nmeasures to protect data consistency, or in other cases where taking advantage\nof the synced database for storing the configuration would be convenient.\n\nConfiguration is stored in the same git-based database as your feeds and posts,\nso settings automatically sync across all your devices.\n\n### Custom default query\n\nBy default, `blog` with no arguments shows unread posts from the last 3 months\ngrouped by week. You can change this:\n\n```bash\n# Show posts from the past 3 months grouped by date instead\nblog config set default_query '.all /d 3m..'\n\n# Show unread posts from the last week\nblog config set default_query '.unread 1w..'\n\n# Reset to built-in default\nblog config unset default_query\n```\n\n### Ingest filter\n\nYou can configure a [jq](https://jqlang.github.io/jq/) expression that\ntransforms posts during `blog sync`, before they are stored. This lets you\nfilter out unwanted content or rewrite fields. The expression receives an array\nof post objects and must return an array.\n\n`blogtato` calls [jq](https://jqlang.github.io/jq/) as an external process. It\nis not bundled with `blogtato`\n\n- it is an optional runtime dependency, only needed if you configure an\n  `ingest_filter`. When no filter is set, all posts are stored as-is.\n\n`jq` was chosen over arbitrary shell scripting because feed data is structured\nJSON, which is difficult to manipulate correctly with most other shell tools,\nso users would otherwise just create shell script files that are a boilerplate\nwrapper over `jq`. `jq` is the standard tool for this purpose that most CLI\nusers already have installed and are familiar with.\n\nAlso, calling an arbitrary binary/script file would be a runtime dependency\nthat does not automatically sync to other machines, so one could easily create\nruntime errors or load inconsistent data in the database. Storing a `jq`\nexpression in the synced database means it automatically carries over to all\nyour devices.\n\n```bash\n# Filter out sponsored posts\nblog config set ingest_filter '[.[] | select(.title | startswith(\"[Sponsored]\") or contains(\"Partner Content\") | not)]'\n\n# Strip tracking parameters from links\nblog config set ingest_filter '[.[] | .link |= sub(\"\\\\?utm.*\"; \"\")]'\n\n# Combine both: filter sponsored posts and strip tracking parameters\nblog config set ingest_filter '[.[] | select(.title | startswith(\"[Sponsored]\") or contains(\"Partner Content\") | not) | .link |= sub(\"\\\\?utm.*\"; \"\")]'\n\n# Remove the filter\nblog config unset ingest_filter\n```\n\nEach post object has these fields: `title`, `date`, `link`, `raw_id`, `feed`.\n\n## Naming\n\nThe naming is meant to symbolize simplicity and pragmatic silliness: I just\nmashed the word \"blog\" together with the first word I could think of: potato.\n\n## Comparison with alternatives\n\n`blogtato` is relatively new and there are several good, and more mature\nalternatives. This section attempts to summarize how they differ from\n`blogtato` and why some users might still prefer to use `blogtato` instead.\n\n### [Newsboat](https://newsboat.org/)\n\nNewsboat is a very mature TUI RSS client with a wide range of features that\n`blogtato` does *not* have. Just like `blogtato`, it supports local-only\nworkflows.\n\nIt can also act as a client to remote servers, so if you are ok with having to\nself-host a server or signing up to a hosted server, then `blogtato`'s `git`\nsync feature is not a relevant differentiator for you.\n\nAnother reason why `blogtato` might be relevant to you is that it has a\nTaskwarrior-like interface that is even more minimalistic than Newsboat.\n\n### [Newsraft](https://codeberg.org/newsraft/newsraft)\n\nNewsraft is a more minimalistic alternative to Newsboat. The\n[Newsboat](#newsboat) breakdown mostly applies.\n\n### [FreshRSS](https://freshrss.org/), [Miniflux](https://miniflux.app/) \u0026 [Tiny Tiny RSS](https://tt-rss.org/)\n\nThese are mature, self-hostable web-based RSS readers/aggregators. What\n`blogtato` offers in comparison is a minimalistic CLI interface and effectively\nzero-setup sync between different machines using `git`, without the need for an\nadditional, continuously running server.\n\n### [Feedly](https://feedly.com/), [Inoreader](https://www.inoreader.com/)\n\nThese are full-featured web-based services. If you are a heavy RSS-user and\nlike the user interfaces and features they offer (such as GUI apps for iOS and\nAndroid, content recommendations) you will likely prefer one of these options.\n\nYou could find `blogtato` interesting if you'd prefer a more minimalistic,\ndistraction-free CLI interface and do not need their advanced features.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkantord%2Fblogtato","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkantord%2Fblogtato","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkantord%2Fblogtato/lists"}