livedoor Reader風のターミナルRSSリーダーを音声だけで実装してみた

はじめに

今日はターミナル上で動くRSSリーダー、termfeedを作ったので、それについて紹介しようと思います。

開発背景

少し前までは、livedoor Readerのようなウェブ上で動くRSSリーダーを使っていた人が多かったと思います。しかし、livedoor Readerがサービス終了してしまい、現在はRSSリーダー自体を使わなくなった人や、若い世代ではRSSリーダーを使ったことがない人も多いのではないでしょうか。

情報収集がTwitterなどRSSがないものに偏っていて、情報を取り逃したり、またはTwitterのおすすめのアルゴリズムに左右されてしまうといったこともあるので、高速にRSSのような自分で取捨選択をした情報源から情報を得るものが欲しいなと思っていました。

世の中にあるものを使ってもよいのですが、最近Claude Codeのようなターミナルのインターフェイスが結構簡単に作れるということを知ったので、それを試してみたいということもありました。

termfeedの特徴

ターミナル上で動くRSSリーダー、termfeedというものを作ってみました。大いにlivedoor Readerをリスペクトしています。

キーバインド

livedoor Readerのキーバインドにかなり似せた作りになっています。

  • jkのキーで記事を前後移動できる
  • saのキーでブログの選択を前後移動できる
  • pでピンをためておいて、oでブラウザーで開くことができる

データ管理

データベースはSQLiteをファイルで持つので、たとえばDropboxのようなところにファイルを置いておいて、複数のPCから同じ情報を参照できます。たとえばNFS上にも置けます。

MCPサーバー連携

コマンドラインからMCPのサーバーも立ち上げられるので、たとえば未読の記事をClaude Codeのようなエージェントに表示してもらって、気になる記事に対してそのままClaude Codeと会話できます。たとえば「こういった内容が紹介されているけど、これってどういう意味か?」「ソフトウェアエンジニアリングの分野でこれが流行っているようだけど、データエンジニアリングの分野ではどういう意味か?」といったことを話したりできます。

npx termfeed mcp-server

そういう接続ができるのは普通のRSSリーダーにはない面白いところだと思います。余談ですが、こういった技術的な雑談を私は結構Claude Codeとしていたりします。

RSS登録機能

RSSの登録については、シンプルなテキストファイルからのインポートや、OPMLからの取り込みもサポートしています。すでにRSSリーダーを使っている人でも簡単に乗り換えられると思います。

npx termfeed add https://www.yasuhisay.info/rss
npx termfeed import subscriptions.opml

使い方

チュートリアル用のサブコマンドも用意しているので、どのように動くのかは簡単に試してもらえると思います。npxのコマンドを打つだけで動くので、ぜひ試してみてください。

npx termfeed tutorial

開発手法と開発時間

音声入力による開発

作り方の特徴としては、このリポジトリで自分ではキーボードはエンターキーぐらいしか押していなくて、入力のほぼ99.9%を音声入力のみで行うということをやっていました。音声入力はWillow Voiceを使いました。

最初は本当にVibe Coding的なノリで欲しいものの仕様を、たとえば「2ペインになっていて、キーボードショートカットはこういう感じで」といったことを言って作らせるということをやっていました。

開発時間

おおむね5時間くらいかかったのですが、おそらくここの5時間は私の指示の上手さ加減によるというところがあるので、上手い人だとたとえば1時間でできるかもしれません。Node.jsに慣れていなかったり、inkのような初めてのライブラリもあったため、私自身がコードを書いていたらおそらく5時間以上かかったと思います。

それでも5時間くらいで、ひとまずターミナルでキーボード操作でRSSをパッと見られるものができたというのはすごく面白い経験でした。本当に声だけでやっていたので、ちょうど週末に作っていたのですが、週末の合間で音声で指示を出しながら、休憩の間にClaude Codeが作業を進めてもらいました。5時間つきっきりかというと、そうでもなかったため、すごく気楽に作れたというのもよかったです。

技術的な発見

TUIライブラリの利便性

これを作っている過程で面白いなと思ったことがいくつかあり、そのうちの1つ目がTUI(ターミナルユーザーインターフェース)を作るためのライブラリであinkというライブラリが簡単に使えてよかったということです。

私はフロント周りはあまり詳しくないため、例えばCSSをどうやって書いたらよいのかプラクティスをあまり知らない点が多いです。しかし、termfeedだとターミナルで動くということもあり、あまり複雑すぎたりきれいにしすぎることも逆に難しいです。そのため、制約があり、細かいところにつまづかないというのはよいところですね。

Reactベースで書けるため宣言的にできるというところもあるし、ターミナルなのに(?)スナップショットテストも普通に書けるというのは結構面白いというか書きやすいところでした。

TUIツールの応用可能性

たとえばデータ系の仕事をしている人などだと、データを1000件くらい眺めた上でアノテーションをしないといけないとか、傾向を眺める必要があるのにJSONがネストしまくっていて見にくいといったことがあると思います。こういうコマンドライン、TUIのツールをサクッと作れるため、そういう場面でも活躍の場所がありそうなツールだと感じました。

プロトタイプ後の課題と改善

CommonJSからESModuleへの移行

一方、機能追加や改善といったことをやろうとすると、逆に結構大変になったこともありました。動くものはできたため、最初はコードをほとんど見ずにapproveしてマージしていました。しかし後になって、inkなどのライブラリがESModuleでないと動かないことが判明しました。実はCommonJSで書かれていたことに、その時初めて気づいたのです。

CommonJSからESModuleの置き換えでClaude Codeは結構苦戦したりしていました。最初にどういう感じで作ってほしいといった内容をVibe Codingでも指示しておくべきでした。本当にプロトタイプならよいのですが、ちゃんとメンテしていきたい場合はそこも指定しておくのがよかったのだと思います。

アーキテクチャの劣化

リポジトリ内のアーキテクチャもおおむね指定していたはずでしたが、Claude Codeは徐々にレイヤリングを無視して、コントローラーから直接モデルを参照したり、コントローラーにロジックを書き始めるなど、かなり自由に実装するようになってしまいました。1個のプルリクエストの最初などでは指示していたつもりでしたが、だんだんコンテキストが薄まってその辺を守らなくなることが起きたりしていました。

レビュー用エージェントの活用

そういった時は、コードを書かせるエージェントにさまざまなことを考えさせるというよりも、レビュー用のエージェントを立てて、このリポジトリの問題点などを挙げさせて、どういう順番でやっていくとよいかというところを考えさせて、それに沿って少しずつ改善させていくといったことをやっていました。

本当に一気に作ったせいで、レイヤリングといった部分をきれいにしていく作業でおそらく10個くらいプルリクエストを作る羽目になったので、トータルで早かったのか遅かったのかはよく分からないところがありました。

また、私自身がレビューするときにはreviewitを活用しました。ファイル名や行数を自分で指定する必要がないので、さくさくレビューができて非常に便利でした。

テストの重要性

最初Vibe Codingでやっていたということもあって、機能を追加するときなどに結構デグレしまくるといったことがあって、これは問題だと思ったためテストを書こうと思ったのですが、テストを書きやすいような作りになっていなかったということもありました。今度から似たような実装をする際には、最初からモジュールシステムやアーキテクチャ設計はある程度詰めてやろうかなと思います。

最初はE2Eで本当に大まかな仕様をテストとして実装させ、ひとまずそこが崩れないようにtestableな感じに少しずつ直していくということをやらせました。

まとめ

音声入力だろうとVibe Codingだろうと、メンテナンスしやすいというところは根本は変わらないのだということを実感しました。やはりこの辺はエンジニアリング力がまだまだ必要ですね。

このような課題もありつつ、そういう動くものが4~5時間くらいでパッと動くものができてしまうというのはモチベーション的にもやりやすかったです。仕事をやりながらだとこうしたやる気を集めてくるのは大変ではあるので。

今後もこういうものを作りたいという場面が出てくると思うのですが、そういう時はClaude Codeのようなものの力を借りつつ、実装していくといったことをやっていきたいなと思います。