四谷ラボ公式ブログ

四谷ラボはいつでも誰でも自由に参加・研究・交流・発信のできる街のオープンイノベーションラボ

Webアプリでタイル型ウィンドウマネージャーなNostrクライアントを作り始めた

こんにちは、lkjsxcです。

ふと思い立って、タイル型ウィンドウマネージャーっぽく使えるNostrクライアントを作り始めました。

github.com

lkjstr

lkjstr は、Webブラウザ上で動くNostrクライアントです。

ブラウザ完結、タイル型UI、実行時情報による最適化あたりをコンセプトにしています。

Home、検索、投稿詳細、ユーザープロフィール、設定、統計情報を、ひとつの画面に複数並べて使う想定です。vscodeやzedで必要なタイルを並べて作業するような感覚。

lkjstrのスクリーンショット

Nostr

このアプリは、Nostrプロトコルに寄り添って作られています。

Nostrとは、中央サーバーに依存しないSNS・メッセージング用の通信プロトコルです。

ユーザーは公開鍵と秘密鍵のペアを持ちます。公開鍵はアカウントのIDに近く、秘密鍵は投稿などへの署名に使います。投稿、プロフィール、リアクションなどはイベントとして扱われ、クライアントはそれを作って署名してリレーへ送り、リレーはリクエストに応じて返します。

特定のサービスにアカウントや投稿が閉じるわけではないので、あるクライアントで作ったイベントを別のクライアントで読んだり、いくつかリレーが使えなくなったとしても、他のリレーからイベントを取ってくることができます。

個々のリレーはイベントを受け取らなかったり消したりもできるので、「必ず消されない」「必ず全員に届く」とは言い切れません。それでも、クライアントを選べること、リレーを選べること、公開鍵で同一性を保てること、複数の場所にイベントを複製できることなど、たくさんのメリットがあります。

分散していると

Nostrクライアントは基本的に複数のリレーと通信します。

リレーは全イベントを持っているわけではなく、レスポンスの速さもバラバラです。あるリレーからはすぐ返ってきて、別のリレーからは遅れてくる。しかも遅いリレーから、他では取れなかったイベントが届くこともありがちです。

検索も同じで、NIP-50対応のリレーならどこでも同じ結果が出るわけではなく、リレーによって返ってくるものが全然違います。新しい投稿を取りたいのに古いものばかり返ってくることもある。

複数リレーから同じイベントが届くので重複排除が必要で、遅いリレーを待つかどうかの判断もあります(待てば取りこぼしは減るが体験が落ちる)。このあたりがNostrクライアントを作る上での面倒なところになります。

最適化

lkjstr では、最初のイベントが返るまでの時間、EOSEまでの時間、イベント数、タイムアウト、エラー、検索結果などを記録して、リクエストの内容やタイミング、遅いリレーの扱いを動的に調節しています。

まだ完璧ではありませんが、何も工夫しなければ多くのリソースを無駄に消費してしまうので、ここは手を抜けません。

キャッシュ

Nostrクライアントにおいて、キャッシュは非常に重要な要素です。

複数タイル設計では、同じイベントに何度もアクセスしがちであるため、lkjstr ではローカルで永続化しています。

しかしながら、中途半端にキャッシュを扱うと、本来リレーに問い合わせて取得すべき投稿を逃してしまうこともあります。

どのリレーを、どの条件で、どの時間範囲まで読んだか——その記録が適切に管理されていないと、リレーへの問い合わせを減らしていいかどうか判断できません。イベントのキャッシュそのものと「確実に読み込めた範囲」を両方扱う必要があります。

署名まわり

署名は、NIP-07ブラウザ拡張に対応しています。

NIP-07はWebアプリがブラウザ拡張を通じて公開鍵取得やイベント署名を行う仕組みで、Webアプリ側が秘密鍵を直接持たずに済むのがポイントです。

パスキーの対応も考えてはいますが、まだ実現していません。

開発とAI

このプロジェクトの開発は、そのほとんどをAIに委ねています。

ドキュメントに重きを置いており、なるべく先に文書を書き、判断や設計の理由を残し、AIが読み返せる形を維持しています。

2026年5月30日時点で、docsは177本・約9,117行、srcは567本・約38,736行、testsは約20,920行。初回コミットは2026年5月17日で、この時点のコミット数は373。srcに200行を超えるファイルはなく、docsに300行を超えるMarkdownもありません。

docsツリー

おわりに

好奇心駆動のふらふら開発ではありますが、より良いアプリを目指して頑張りたいなーと考えています。

RTX3070でフルスクラッチなLLMとAIエージェントを作り始めた

はじめに

こんにちは、lkjsxcです。

しばらく前の話になりますが、私は中学2年生の頃にGPT-3の存在を知り、とても大きな衝撃を受けました。

当時の私は、Scratch上で動作するプログラミング言語を趣味で作っていました。しかし、GPT-3を知ってから、関心の中心が一気にAIへ移りました。

もともと何かを自作することが好きだったので、自然とAIも自分で作ってみたいと思うようになりました。

しかし、現実はそう簡単ではありません。こだわりの強さ、集中力の波、資金不足、計算資源の不足、そして単純な実装力不足もあり、長い間、自分の手でそれらしいものを作るところまでは到達できませんでした。

大学2年になったこの春、(ChatGPTなどAIサービスへの課金が功を奏し、)ようやく自分の手元で、フルスクラッチのLLMとAIエージェントの形を作ることができました。

学習に使ったのは、自室の机の上にある、GeForce RTX 3070 8GBを積んだゲーミングPCです。

一般論として、LLMの開発には大きな計算資源が必要です。しかし今回使ったのは、特別なサーバーでも、クラウドGPUでもありません。2023年の春頃、中古市場に13万円弱で売られていたごく普通のゲーミングPCです。

その限られた環境で、ランダムな初期状態から小さな言語モデルを学習し、AIエージェントとして動く仕組みまでを作りました。

作ったもの

AIエージェントを、LLMからフルスクラッチで作りました。

github.com

ここでいう「フルスクラッチ」とは、既存のAIを改造したものではない、という意味です。公開されている基底モデルから追加学習したものでもありません。

ランダムなパラメータから、小さなデコーダ型Transformerを学習させ、そのモデルを中心にAIエージェントとして動く仕組みを作りました。

現在は次のような構成になっています。

  • RTX 3070 8GBで学習する、小さなフルスクラッチLLM
  • 学習済みモデルを読み込むPython / PyTorch製の推論サーバー
  • 推論サーバーを呼び出すRust製のWeb UI兼エージェント実行基盤
  • ファイル読み書き、シェル実行、Web取得、メモリ検索、メモリ書き込みなどのツール群
  • モデルがXML風のアクションを出力し、それをランタイムが検証して実行する仕組み

単に「質問を投げると文章が返ってくる」だけのものではありません。

モデルは、必要に応じてツールを選びます。

たとえば、ワークスペースの中身を確認するなら fs.list を呼び、ファイルを読むなら fs.read を呼び、記憶を検索するなら memory.search を呼びます。最後にユーザーへ返答するときは agent.finish を呼ぶ、という形です。

最初の構想では、JSONでアクションを出力させることを考えていました。

しかし、現在のlkjaiではXML風の形式を採用しています。

小さなモデルにとって、厳密なJSONを安定して出力し続けることは非常に難しいです。引用符、カンマ、エスケープ、括弧の対応など、破綻する場所が多すぎます。

そこで、現在は次のような設計にしています。

モデルには、短く、見通しのよい、1個だけのアクションを出してもらう。

そのアクションをRust側で検証し、問題なければツールを実行し、結果をまたモデルに返します。これを最大ステップ数まで繰り返します。

Web UIを開くと、ユーザーの発言、モデルの簡単な理由、ツール呼び出し、ツール結果、最終回答などが順番に表示されます。

見た目としては、かなりAIエージェントらしくなっています。

それらしい様子1

それらしい様子2

現実

しかし、残念ながらそう思うようには行きません。

現時点のlkjaiは、まだ実用的なAIエージェントではありません。

エージェントの器はできています。学習パイプラインもあります。推論サーバーも立ちます。Web UIも動きます。ツール呼び出しもできます。評価の仕組みもあります。

しかし、中心にいる小さなLLMが弱すぎる。

簡単な挨拶に対して、なぜか関係ないファイルを読みにいくことがあります。存在しないドキュメントを読もうとすることもあります。XML風の出力にはなっているのに、行動としては正しくない、というケースもあります。

だめそうな様子1

だめそうな様子2

しかし、そう悪いことでもないと考えています。

過去の私では、そもそもモデルを学習させ、推論し、エージェントとして評価するところまで到達できていませんでした。

ここまで来てようやく「まともに失敗できる場所」に立てた、という感覚があります。

これは、私にとって大きな前進です。

RTX 3070 8GB

今回の一番大きな制約は、やはりGPUでした。

ただし、RTX 3070が悪いという話ではありません。むしろ、よく動いてくれています。

このGPUは本来、ゲーム用途のGPUです。巨大なLLMを学習するためのものではありません。それでも、小さなTransformerを学習し、推論し、評価を回すところまでは問題なく付き合ってくれました。

問題は、LLMというもの自体があまりにも大きいことです。

現在のlkjaiのデフォルトモデルは、lkjai-scratch-40m です。名前の通り、およそ4000万パラメータのモデルです。

構成は次のようになっています。

  • 語彙数:8192
  • コンテキスト長:1024
  • 層数:10
  • hidden size:576
  • attention heads:8
  • KV heads:2
  • FFN size:1536

アーキテクチャとしては、RMSNorm、RoPE、Grouped-Query Attention、SwiGLU、tied embeddingsなど、現代的なLLMでよく使われる要素を素直に採用しています。

しかしながら、どれだけ現代的な要素を集めても、4000万パラメータはLLMとしては小さくなります。

現在広く使われている実用的なLLMは、数十億、数百億、数千億、あるいはそれ以上のパラメータを持ち、膨大なデータと計算資源によって学習されています。

それらと比べると、lkjai-scratch-40m は本当に小さいモデルです。

そして、フルスクラッチ学習では、より一層その小ささが厳しく現れます。

既存の基底モデルを使う場合、そのモデルはすでに大量の文章を読み、言語の基本、常識、指示追従などをある程度身につけています。

しかし、フルスクラッチでは違います。

最初のモデルは、ただの乱数です。最初は支離滅裂なトークン列を出すことしかできません。

さらに、RTX 3070に搭載されている8GBのVRAMに収めるためには、モデルサイズ、コンテキスト長、バッチサイズなど、さまざまな要素を削る必要があります。

ここしばらくの開発は、調査とトライアンドエラーの繰り返しでした。

アーキテクチャを見直す。出力が崩れたら教師データを見直す。評価を見直す。プロンプトを見直す。設定を変えてまた学習を回す。

最初は「RTX 3070でLLMを作る」という響きに面白さを感じていました。

今も、その面白さはあります。

ただし、それは「ありふれたゲーミングPCで、すごいAIができました」という派手なものではありません。

実際には、一日中聞こえてくるGPUファンの音をBGMに、学習ログと評価結果を見て、少しずつ原因を切り分けていく地味な作業です。

もちろん、vast.aiなどのクラウドサービスに課金し、H200のようなGPUを借りれば、開発速度は大幅に向上すると思います。より大きく、より賢いモデルも作りやすくなるでしょう。

それでも、自宅のゲーミングPCに縛って頑張ることには、独特の面白さ、ロマンがあります。

なぜフルスクラッチなのか

「わざわざゼロから作る意味があるのか」

これはかなり自然な疑問です。

実用的なAIエージェントを作りたいだけなら、公開されている強い基底モデルを使った方が確実です。

その方が圧倒的に賢いです。モデルによっては多言語も扱えます。ツール呼び出しも安定しています。コードも書けます。複雑な推論もできます。

わざわざRTX 3070で、小さなモデルを乱数から学習させる必要はありません。

しかしそれでも、私は確かめたかったのです。

自分の部屋にあるゲーミングPCだけで、限られた計算資源の中で、どこまで行けるのか。

このプロジェクトは実用性というより、好奇心に近い動機で進んでいます。

モデル

主な仕様は以下の通りです。

  • パラメータ数:約4000万
  • 語彙数:8192
  • コンテキスト長:1024トークン
  • 層数:10
  • hidden size:576
  • attention heads:8
  • KV heads:2
  • FFN size:1536
  • アーキテクチャ:RMSNorm、RoPE、Grouped-Query Attention、SwiGLU、tied embeddings
  • 学習開始:ランダム初期化

モデルとしては、Llama系の現代的なデコーダモデルを、RTX 3070 8GBに収まるように小さくしたもの、と考えると分かりやすいと思います。

ただし、規模はまったく違います。

このモデルに、巨大なLLMのような知能は期待できません。

学習

学習は大きく分けて、次の2段階を想定しています。

  1. causal_lm_full による通常の次トークン予測
  2. assistant_masked_sft によるXMLアクション形式の教師あり学習

前者では、公開コーパスの文章を使って、言語モデルとしての基本を学習させます。

現在の方針では、商用利用上の安全性も意識し、明示的に許容されたライセンスの公開データを使うことにしています。

後者では、lkjaiが実際に使うXML風アクション、ツール選択、メモリ操作などを学習させます。

ここで重要なのは、SFTではユーザー発話やシステム文ではなく、アシスタントの出力部分を中心に損失をかけることです。

モデルに「この文脈では、このアクションを出す」という対応を学ばせます。

エージェントループ

1回のユーザー入力に対して、lkjaiは次のように動きます。

  1. ユーザー発話を記録する
  2. 直近の会話履歴を読む
  3. 古い履歴があればローリングサマリーを読む
  4. 関連する永続メモリを検索する
  5. モデルサーバーが生きているか確認する
  6. システム方針、ツール一覧、メモリ、最近の文脈をまとめてプロンプトを作る
  7. モデルに1つのXML風アクションを出させる
  8. そのアクションを検証する
  9. reasoning があれば短い可視イベントとして表示する
  10. ツールを実行する
  11. 結果を観察として追加する
  12. agent.finish が出るか、最大ステップ数に達するまで繰り返す

最大ステップ数は、デフォルトでは6です。

モデルの出力が壊れていた場合は、修復を1回だけ試します。

同じ非終端アクションを繰り返した場合は、repeat_action として止めます。

この仕組み自体は、AIエージェントとしてはかなり一般的な構成です。

ただし、中心のモデルが弱いと普通に壊れます。

そして今は、まさにそこが主な問題になっています。

厳しい結果

テストの上では、lkjaiはまだ賢いとは言えません。

固定評価では、モデル、トークナイザ、エクスポート、設定など、成果物として必要なものが揃っているかを見ています。ここはかなり改善してきました。

一方で、実際にモデルを推論させ、正しい行動を取れるかを見るために設けたテストでは、まだほとんど通っていません。

直近の記録は 0/200 です。

つまり、200件のホールドアウトケースに対して、合格したものが0件でした。

これは厳しい結果です。最初に見たときは非常に落ち込みました。

しかし、少し冷静になると、これはある意味では妥当でもあります。

小さなモデルに対して、いきなり次のようなことを求めています。

  • 挨拶なら余計なツールを呼ばずに返答する
  • ファイルが必要なら正しいツールを選ぶ
  • 存在しないファイルを読もうとしない
  • 失敗したツール呼び出しを同じまま繰り返さない
  • 更新前には確認を要求する
  • XMLの形を壊さない
  • 最後は agent.finish で終わる

人間から見ると簡単に見えます。

しかし、4000万パラメータのフルスクラッチなモデルにとっては、荷が重すぎました。

自宅のゲーミングPCで全部動かす

今回の開発で一番面白かったのは、自宅のPCで一通りの流れが完結していることでした。

学習も、推論も、Web UIも、評価も、自分の机の上で動きます。

lossが下がる。チェックポイントが保存される。推論サーバーが立ち上がる。Web UIからメッセージを送る。モデルが変なXMLを返す。それを見て、データやプロンプトや評価を直す。

この一連の流れには、クラウドのAPIを叩くだけでは得難い手触りがあります。

一方で、この計算機の限界もかなりはっきり見えました。

RTX 3070 8GBでは、できることとできないことの差がはっきりしています。

小さなモデルを学習することはできます。小さなモデルを推論することもできます。学習パイプラインを作り、評価を回し、改善サイクルを作ることもできます。

しかし、実用的で強い言語能力を持つモデルをフルスクラッチで作るには、圧倒的に足りません。

おそらく、このプロジェクトの本質はそこにあります。

「RTX 3070でもLLMを作れる」という話ではあります。

しかし、それ以上に、「RTX 3070で作ると、LLMの厳しさがよく分かる」という話でもあります。

今後

まず、教師データをより充実させ、XMLアクションの基礎を安定させます。

モデルが正しい形式を出せないなら、ツール実行以前の問題です。

まずは、短く、壊れていない、1個だけのアクションを出せるようにする必要があります。

その上で、ファイル読み取り、一覧取得、メモリ検索のような読み取り系ツールを順番に安定させます。

学習面では、公開事前学習コーパスと、first-partyなXMLアクションSFTコーパスをもっと丁寧に作り直す必要があります。

さらに、挨拶、短い質問、ツール不要の返答、ファイル操作、メモリ操作を分け、それぞれの評価も分ける。

そうしないと、どこが良くなったのか分かりません。

また、モデルサイズについて、将来的には200M前後のものにも興味があります。

しかしながら、モデルを大きくするとその分必要な計算量も増えます。

データや評価が悪いまま大きくしても、おそらくあまり意味がありません。

まずは個人で辿り着ける40Mの限界に挑むつもりです。

おわりに

中学2年生の春、GPT-3に衝撃を受け、AIに強い関心を持つようになりました。

そこから何度も試行錯誤して、今回ようやく、自分の手元でフルスクラッチなLLMとAIエージェントの形を作ることができました。

ただし、それは強いAIではありません。

テストも通りません。挨拶で変なツールを呼ぶことがあります。XMLも壊れます。簡単なベンチマークですら結果は散々です。

それでも、ランダムな重みから始めて、モデルを学習し、推論し、エージェントとして動かし、失敗を観測できるところまで来ました。

これは、自分にとって大きな一歩でした。

このプロジェクトは、まだ完成していません。

むしろ、ようやく本当のスタート地点に立ったくらいです。

おわりに2

この記事を書き終えてから気がついたのですが、今のモデルはまだ通算で50時間ほどしか学習していません。

自宅のGPUを回している体感としてはそれなりに長いのですが、LLMの学習として見ると、50時間はかなり短いです。

もちろん、ただ長く学習させれば急に賢くなる、という単純な話ではありません。データの質、学習率、SFTの作り方、評価設計など、見るべきところはまだたくさんあります。

それでも、数週間、あるいは数ヶ月単位で学習を続けたら、今より少しはまともな挙動になるのではないか、という期待はあります。

現在進行系で、自室のRTX3070は学習を続けています。

おわりに3

現状のlkjaiは、まだ実用的な段階にありません。

しかしながら、学習パイプライン、推論サーバー、Web UI、ツール実行、評価の仕組みまでは一通り揃ってきました。

つまり、あとは中心にいるモデルをどう育てるか、という話になりつつあります。

......ところでふと、全力機械株式会社様からご支援いただいた資金が、ありがたいことにまだいくらか残っていることに気が付きました。

来月はその資金を使って、TPUやクラウドGPUを借り、フルスクラッチにこだわらず、「実用的なAIエージェント」の開発に挑戦したいと考えています。

私のAIへの熱意は、もうしばらく冷めそうにありません。

Bluesky Meetup in Tokyo vol.4 を終えて

はいどーも!!Shino3 (@shino3.net) です!!しのさんと読みます。

先日はBluesky Meetupにご参加いただきまして、ホントに皆様ありがとうございました!Blueskyの利用者数が増えたことやサービス開始3周年、そしてカントリーマネージャーに高野さん (@naoko.cc) が抜擢されたこともあり、今回のVol.4イベント開催に至りました。えっ、もう4回もやったの!?

いつもの方やその友人でご新規の方にも来場いただき、懇親会ではSNSが大好き!という方まで。本当にありがとうございます。Findy株式会社さま (@findy-code.bsky.social) の会場協力もあり、100名近い参加者と時を共にすることが叶いました!また四谷ラボとして私も今回お手伝いできてとても嬉しかったです!さて、イベントレポートのカタチでブログを書いていますが、皆様の面白い話や温度感は以下にYouTubeがあり、いつでも振り替えれるようになっております。通勤時間とかにご自身のペースで見るとかもいいかも!

また今回の配信はまめもさん (@mamemomonga.bsky.social) とキョンジーさん (kyong.tokyo) ご協力いただきました!過去最高の画質と音質でお届けできております。

www.youtube.com

イベントの様子

イベントの司会進行・アナウンスは今回の企画からお手伝いいただいているこぎそさん (@kgsi.bsky.social) のタイトルコールで始まりました。 最初にドリンクなどを皆様のお手元に。高野さんの乾杯から始まります!

メインセッション1「Bluesky 日本コミュニティの推移」

Photo by: @tomihisa.social on Bluesky

これは私、Shino3(しのさん)の登壇です。サービスリリースから現在までの歩み、またBlueskyが「代替SNS」を超えるもっと魅力的な「分散型であることの良さ」にフォーカスして喋ってみました。

前段でBluesky(AT Protocol)を構築する分散型アーキテクチャの話を少々。でも実際使っている人が「分散型かどうか?」はあまり関係ないよね!と・・・。分散型であることのメリットやどう我々が分散型に向き合うことができるのかの話などさせていただきました。 2023年3月のβテスト開始時は一部のSNSやコミュニティで話題になってユーザーが流入したこと、初期にエンジニアが多くものすごい勢いでクライアントアプリやサードパーティのサービスが開発されていたこと、Bluesky運営のWhyさんが来日したときにMeetup開催に至った経緯などをご紹介しました。(サービス開始一ヶ月での出来事) その後、招待制でのユーザー増加や他のSNS障害や改悪といった外部要因でのユーザー数の増加と定着に関するお話を2026年現在に至るまでの経緯を振り返っています。

メインセッション2「2026年最新Bluesky動向」

Photo by: @moja.blue on Bluesky

2025年よりBlueskyのカントリーマネージャーに就任された、高野さんの登壇です。カントリーマネージャーとはBlueskyチームの中で日本という大きな市場を担当する専任者で、ユーザーとBlueskyチームの架け橋になってくれるそんな方です。

主な内容はBlueskyの現在地のお話。登録者数4320万人を超えた今、日本は世界で見ても2番目に活発な利用があります。そんなBlueskyですが社員は40人、エンジニアは約半分のチームメンバーで支えられているとのこと。現在地では待望の下書き機能実装や、翻訳の追加がされたところ。今後はグループチャットの実装や検索・画像まわりの強化にも力を入れていきたいという展望も発表されています

内容はYouTubeのアーカイブのほか、当日の産経新聞さんの取材に詳しく記載されております!

www.sankei.com

コラボ発表!!!!!

クリエイタープラットフォーム「GENSEKI」さんによるBlueskyのコラボイベントが発表されています!!

bsky.app

Bluesky協賛による第一回「春を感じる主線なしイラストコンテスト」が開催! 参加方法などはGENSEKIさんの投稿より

\ 🌸✨本日開始!✨🌸/   くにたろ先生審査員  「春を感じる主線なしイラストコンテスト」 を開催いたします! 柔らかい雰囲気を持つ主線なしイラスト 春をテーマに描いてみませんか? ご応募はこちらから👇 genseki.me/compes/YV65G...

GENSEKI【公式】 (@genseki.me) 2026-04-10T01:59:25.005Z
bsky.app

LTセッション1「Atprotoとバイブ コーディングで 広がるBlueskyの 可能性」

Photo by: @moja.blue on Bluesky

がるさん (@garuneko.com) BlueskyのアプリをiPadで見るとどうですか…?という問いから始まる内容。そうですね、見た目がすごいことになりますよね…?今の時代なので、バイブコーディングをフル活用して作ってしまえ!というお話。令和だ…!

実際に開発されているiPad向けクライアントアプリケーション「Aerune」は以下のリンクより!

Aerune

Aerune

  • MITSUKI HAMADA
  • ソーシャルネットワーキング
  • 無料
apps.apple.com

デザインが洗練されていて可愛く、タブレットでも快適に使えるよう工夫をこらしておられます。

LTセッション2「ネットでのいざこざに疲れました... Blueskyへの期待と展望」

Shotaro Tsuda さん (@brighthelmer.bsky.social) のタイトルは「ネットのいざこざに疲れました…」から始まるご自身でのSNSにおける炎上体験やタイムラインにおける話題のお話。トークがとてもおもしろいです! YouTubeにアーカイブがありまして、是非ご覧いただきたい内容になっています!!

懇親会

Photo by: @tocatti.bsky.social on Bluesky

イベント後は軽食とドリンクのサービスもあり、懇親会はユーザー間の交流も深まる機会に。一方でもう少し時間が欲しかったなという声もいただいており。タイムラインとかを見ていると「懇親会に参加したかった!」というお声もありましたので、是非次回のイベントはもっと満足度をぶち上げていけるようなイベント運営していけたらと思います!!

ちぃたん☆ もイベントきてくれてありがとう!

Photo by: @hmt.bsky.social on Bluesky

今後のMeetupとイベント

さて、ご参加された皆様ありがとうございました!今回来られなかった方、もしくはあとから知った方は是非、YouTubeアーカイブをご覧ください。

そして直近(というか明日 18日)Bluesky Hackathonがあります! 11:45〜21:00ぐらいまでの長丁場、みんなでものを作り上げて成果発表しようという取り組み!!日本が大きな市場であることも相まってイベントの開催に至りました。

まだまだ参加者はエンジニア以外にも企画やデザイン・イラストレーターや、それ以前に時間管理してくれたりする方も募集中!! 参加されるエンジニアもバイブコーディングでAIを使い倒す、かなりクセの強い方々が多いので、最先端に触れるチャンスかも!?

https://428lab.connpass.com/event/387583/

その他、今年も四谷ラボで関西、九州といろいろ計画しております。続報お楽しみに!!

Bluesky Hackathon イベントガイド

このガイドは、Blueskyのデベロッパー・リレーションズ担当ジム・レイ氏(@jimray.locket.computer)が2026年4月に開催するBluesky Hackathon in Tokyo Vol. 1のために書いた文章を、許可のもとに翻訳したものです。

なおBluesky Hackathon in Tokyo Vol.1 は 2026/4/18 開催の予定となります。参加者募集中!!エンジニアのほか、デザイナーやアイデア出す人、取りまとめる人、発表する人…様々な役割が必要です!「エンジニアじゃないけど…」と思っても興味があったら是非ご参加ください!

https://428lab.connpass.com/event/387583/


⚠️ 注意しておきたいこと

一般的な免責事項および注意事項として、atproto内の公開データはグローバルに配信されます。本プロトコルでは、コンテンツの可視性を制限する機能はまだサポートされていません。つまり、プロジェクトを設計する際にも、エンドユーザーに伝える際にも、細心の注意を払う必要があります。

はじめに

Atprotoは、大きな世界に広がるオープンなソーシャルプロトコルです。ユーザーはJSONレコードをリポジトリに公開します。その後、それらのレコードの変更内容がネットワーク全体で同期され、アプリケーションを駆動します。

コミュニティメンバーであるダン・アブラモフによる以下の素晴らしい記事をお勧めします。

Open Social プロトコル自体がAPIである。
Where it's at:// ハンドルからホスティングまで。
A Social Filesystem アプリケーションよりもフォーマット。

完全なドキュメントは https://atproto.com/docs で入手できます

Atproto上では、既存のインフラストラクチャ、ツール、ユーザーコミュニティを利用して、まったく新しいソーシャルアプリを構築することが可能です。現時点では、他のアプリよりも適しているアプリもあります。ここでは、今日成功する可能性があると考えるいくつかのパターンを紹介します。Statusphere Tutorial と、「What does an AppView Implementation Entail」を参照して、完全なアプリケーションを構築するために必要なものの概要を確認してください。

レビューとレコメンデーション: Atprotoモデルに非常に適合するソーシャルアプリの幅広いカテゴリーとして、ほぼあらゆる種類の施設、コンテンツ、または製品(レストランやイベント会場、企業やサービス、映画やその他のメディア、耐久消費財やハイテク製品など)を対象としたソーシャルレビューおよびレコメンデーションサービスが挙げられます。モデレーション機能(ラベリングやOzoneなど)を活用することで、偽アカウントや評価の操作を抑制することができます。既存のデータベースや識別子(例:IMDB、MusicBrainz、Wikidata、ISBN、SKU)を活用することで、対象の曖昧性を解消できます。また、既存のソーシャルグラフ(Blueskyのフォロワーグラフなど)を活用することで、ソーシャルレコメンデーションの初期構築が可能となります。

質問と回答: 共同ナレッジベース、またはよりカジュアル/ローカルなアドバイスといったものにも適しています。

長文コンテンツ: Atprotoでブログを実装している素晴らしいプロジェクトがすでにいくつかあります。LeafletpcktOffprint などです。より具体的な記事やエッセイの形式は、カスタムインターフェイスとスキーマの恩恵を受ける可能性があります。学術論文、インタラクティブな調査、旅行記や地域ガイド、ルートの説明、技術文書、写真集のような雑誌記事などです。多くの長文アプリケーションは、データエンコーディングのためにstandard.siteのLexiconを使用しています。

SDKとツール

さまざまなプログラミング言語に対応した、多くのファーストパーティおよびコミュニティツールが https://atproto.com/sdks で入手できます。

Claude Codeとatprotoの利用

Claude Codeはatprotoの開発を大幅に加速させることができますが、その使い方を理解することと同様に、どこで役立つか、どこで誤った結果を出してしまうかを把握することも重要です。

atprotoのスキーマシステムであるLexiconは、レコード型、HTTPエンドポイント、イベントストリームメッセージを記述する、機械可読なJSONです。すべてのフィールドには明示的な型、検証制約、および必須/オプションのフラグが設定されています。これにより、Lexiconはコード生成に適した入力となります。文章によるドキュメントとは異なり、エージェントが誤って解釈するような曖昧さがほとんどないからです。

活用のヒント

Lexicon GardenでLexiconを見つける。 コミュニティサイトlexicon.gardenでは、新しいレキシコンを閲覧・発見することができます。さらに便利なことに、各レキシコンには対応するLLMテキストファイルが用意されており、これをAIツールに直接渡すことができます。app.bsky.feed.like用のLLMテキストファイルはこちらです。

Claude Codeには、Lexiconファイルの説明ではなく、ファイルそのものを直接渡す。LexiconのJSONをコンテキストとして貼り付けてください。エージェントが文章(「ステータスフィールドが絵文字になっているレコードが欲しい」)を基に処理を行う場合、フィールド名や型を推測することになり、時に誤った判断を下すことがあります。Lexiconを基に処理を行う場合、実際のスキーマが使用されます。これはファイアホース・コンシューマーの生成にも有効です。各レコードの$typeフィールドにより、Claudeは明示的に指定されなくてもレコードの種類を識別し、フィルタリングすることができます。

リポジトリ操作のコアとなるLexiconも含める。完全なRead/Writeクライアントが必要な場合は、独自のLexiconに加えて、com.atproto.repo.* のLexiconをClaudeに提供してください。これらは、アプリが使用するXRPCメソッド(putRecord, getRecord, listRecords)を定義します。これらがなければ、Claudeはメソッドのシグネチャを推測することになります。これらはatprotoのモノレポ内にあります。

OAuthは明示的に指定する。アプリをスケルトン化する場合、Claudeはアプリパスワードを使用してcreateSessionを呼び出そうとする可能性があります。これは、古いチュートリアルやトレーニングデータでよく見られるレガシーなパターンです。そうしないよう、明確に指示してください。OAuthクライアント実装ガイド、またはTypeScript SDKのOAuthパッケージ(@atproto/oauth-client-browser または @atproto/oauth-client-node)を参照させるようにしてください。SDKがディスカバリー、PKCE、DPoPトークンのバインディングを処理します。その上に、Claudeにアプリケーションロジックを記述させましょう。

FirehoseコンシューマーにはJetstreamを使用する。生のRelay WebSocketストリームは、CARファイル形式でエンコードされたリポジトリイベントを送信しますが、レコードを抽出するにはMerkle Search Treeの解析が必要です。JetstreamはFirehoseを整理されたJSONに変換するため、扱いがはるかに簡単です。ClaudeはJetstream用のコンシューマーを初回から正しく生成しますが、生のRelay形式の場合は事情が異なります。

Claude Codeが苦手な点

新しいLexiconの設計。Claudeは構文的には正しいLexicon JSONを生成しますが、意味論的な側面、例えばNSIDの権限(xyz.statusphere.statusにあるドメインは、権限がstatusphere.xyz であることを意味します)、キー戦略の選択、スキーマの進化に関する制約(フィールドの名前変更や型の変更はできず、互換性を破る変更を行うには新しいNSIDが必要となります)といったことを見落とすことが多いです。Lexiconはご自身で設計し、Claudeを使ってそれに基づいて実装してください。

リッチテキストのファセット。app.bsky.feed.postレコードのファセットバイト範囲は、文字位置ではなく UTF-8 エンコードされたバイトに基づいてインデックス化されます。Claudeは約半数のケースで、文字ベースのインデックスを持つコードを生成します。ファセットを手動で作成するのではなく、SDKのRichTextヘルパーを使用してください。

PDSとAppViewの区別。 Claude、PDS(ユーザーデータが格納されている場所)とAppView(アプリケーションからのクエリ用にデータがインデックス化されている場所)を混同しがちです。PDSからフィードやソーシャルグラフのデータを取得しようとするコードは動作しません。それらはAppViewに存在します。

リソース


自宅サーバーにLXDを導入した

経緯

こんにちは、lkjsxcです。

冬の終わりを実感し始める今日この頃、私は大学のテスト勉強に追われていました。

そして、人は何かに追われているとき、身の回りを整理したくなるものです。

例に漏れず、私も部屋の掃除......もとい自宅サーバの整理を始めてしまいました。

現状、我が家はArchLinuxの入ったミニPC(Ryzen 7 7840HS / 64GB RAM / 2TB Storage)をサーバーとして運用しています。

自宅サーバー。パワフルでありつつ、小さくてかわいい

ここで問題となるのは、このマシンを友人たちにも共有しており、その管理が少々杜撰になっていたということです。

各々のプライバシーや私の技術力との兼ね合いもあり、ルートレスなDockerによって棲み分けがなされていました。

しかしながら、筆者自身がコンソール画面での操作に慣れていなかったため、管理に苦労していました。

特に通信周りがひどく、マインクラフトのサーバーのために大量のポート番号が割り当てられたりなど、非常に厳しい状態にありました。

いつか整理すると友人たちへ宣言し、早1ヶ月。

この機を逃すわけには行くまいとChatGPTに相談したところ、LXDを紹介されました。

リソース管理に優れているLXDコンテナの上でDockerを導入すれば、今まで通りの使用感で開発できるとのこと。なるほど。

早速そのことを友人たちに相談し、116日間動き続けてくれたArchLinuxに感謝を告げ、私はマシンをシャットダウンしました。

導入の流れ

(ここは技術的な備忘録なので、興味のない方は読み飛ばしても問題ありません。)

ホストOS

私はターミナル操作がとても苦手なので、可能な限りWebブラウザから操作するような手順で進めます。

OSのインストール時、LXDのプリインストールにチェックを付けます。他の項目はよしなに。

インストールを終えたら忘れぬうちに、SSHの鍵を交換したり、パスワードによるログインを無効化したりなどします。

さて、ChatGPTの話によるとlxd initと実行するだけで、Webブラウザから管理できる何かが立ち上がるとのこと。

何か対話が始まりますが、全てEnterでスキップしていいとのことなのでEnter連打。

ストレージに関して、zfsはdockerのパフォーマンスを著しく低下させるという話がありますが、よほど古いカーネルを使っていなければ問題ないようです。

たったこれだけで、TCPの8443番にてLXD-UIが立ち上がりました。すごい。

プロファイル

インスタンス上でDockerを動かすために、プロファイルの設定を行います。

Webブラウザ経由では設定できない項目もあるようなので、ホストOSから設定します。

lxc profile set default security.nesting=true
lxc profile set default security.syscalls.intercept.mknod=true
lxc profile set default security.syscalls.intercept.setxattr=true

インスタンスを起動

インスタンスを立ち上げます。

今回、BaseImageはUbuntu 24.04を選択しました。

BaseImageには他にもデスクトップ版などありますが、間にエミュレータが挟まる(オーバーヘッドがとても大きい)vmなども並んでいるので、注意して選ぶ必要があります。

アドレスの固定

velocityなどのプロキシサーバーのために、インスタンスのアドレスを固定します。これもWebブラウザ経由では設定できないので、ホストOSから設定します。(lkjsxc_main, eth0, 10.161.59.3 は内容に応じて適宜書き換える必要があります)

lxc config device override lkjsxc_main eth0 ipv4.address=10.161.59.3

ポートフォワーディング

外からインスタンスへアクセスできるようにします。

設定画面からDevices、Proxyと進み、新しいプロキシデバイスを追加します。

注意すべき点として、ListenのAddressには外側のアドレス(基本的にはホストOSのアドレス)、ConnectのAddressには0.0.0.0が入ります。

Dockerのインストール

インスタンスのTerminalから、Dockerをインストールしていきます。

curl -fsSL https://get.docker.com | sh

この調子で、portainerやnginx、sambaやgiteaなどを導入し、環境を構築していきます(詳しく書くと長くなるので省略)

感想

LXDは本当に素晴らしいものでした。

ぱっと思いつくだけでも、導入が楽・ほとんどの用事がWebブラウザ経由で済む・インスタンス同士の通信が容易・リソースの管理が楽・オーバーヘッドが大きくない、などのメリットが挙げられます。

Webブラウザ経由で一部の設定にアクセスできないことを除けば、本当によくできたシステムだなあと感心します。

数人規模の開発環境において、LXDは最も好ましい選択肢の一つとなりそうです。