<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Granda | Ideas &amp; Code</title><link>https://granda.org/ja/</link><description>Recent content on Granda | Ideas &amp; Code</description><generator>Hugo</generator><language>ja</language><lastBuildDate>Fri, 13 Mar 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://granda.org/ja/index.xml" rel="self" type="application/rss+xml"/><item><title>駐車中のテスラはデータセンターだ</title><link>https://granda.org/ja/2026/03/13/%E9%A7%90%E8%BB%8A%E4%B8%AD%E3%81%AE%E3%83%86%E3%82%B9%E3%83%A9%E3%81%AF%E3%83%87%E3%83%BC%E3%82%BF%E3%82%BB%E3%83%B3%E3%82%BF%E3%83%BC%E3%81%A0/</link><pubDate>Fri, 13 Mar 2026 00:00:00 +0000</pubDate><guid>https://granda.org/ja/2026/03/13/%E9%A7%90%E8%BB%8A%E4%B8%AD%E3%81%AE%E3%83%86%E3%82%B9%E3%83%A9%E3%81%AF%E3%83%87%E3%83%BC%E3%82%BF%E3%82%BB%E3%83%B3%E3%82%BF%E3%83%BC%E3%81%A0/</guid><description>&lt;p&gt;あなたの車は95%の時間、駐車されている。その中には、毎秒300〜500兆回の演算が可能なチップが搭載されており、冷却システム、電力変換、そしてセルラー無線が備わっている。それは何もしていない。&lt;/p&gt;
&lt;p&gt;テスラとxAIはそれを変えようとしている。3月11日、イーロン・マスクは「&lt;a href="https://www.cnbc.com/2026/03/11/musk-unveils-joint-tesla-xai-project-macrohard.html"&gt;Macrohard&lt;/a&gt;」を発表した——内部では「Digital Optimus」と呼ばれる、テスラとxAIの共同プロジェクトだ。駐車中のテスラを個人AIエージェントへと変える。チャットボットではない。あなたの画面を監視し、マウスとキーボードを操作して、実際の作業をこなすエージェントだ。&lt;/p&gt;
&lt;p&gt;この名前はマイクロソフトへの意図的な皮肉だ。このシステムは「企業全体の機能をエミュレートできる」と主張している。誇張ではある。しかし、その根底にあるアーキテクチャは本物であり、ハードウェアはすでに大規模に展開されている。&lt;/p&gt;
&lt;h2 id="ハードウェアはすでにある"&gt;ハードウェアはすでにある&lt;/h2&gt;
&lt;p&gt;テスラはアメリカの道路上に、AI3（旧HW3）またはAI4チップを搭載した約400〜500万台の車両を持っている。AI3は&lt;a href="https://x.com/convequity/status/1802008991314461176"&gt;144 TOPS&lt;/a&gt;を実現し、AI4は&lt;a href="https://x.com/pbeisel/status/1950314514580459698"&gt;300〜500 TOPS&lt;/a&gt;を実現する。2026年末に予定されているAI5は&lt;a href="https://x.com/pbeisel/status/1950314514580459698"&gt;2,000〜2,500 TOPS&lt;/a&gt;まで跳ね上がる。&lt;/p&gt;
&lt;p&gt;これらは汎用CPUではない。自動運転のためのビジョンモデルを低消費電力でパッシブ冷却のまま実行するために設計された、専用のニューラルネットワーク推論アクセラレーターだ。渋滞中のカメラ映像処理に向いている特性は、駐車場でのAIモデル実行にも向いている。&lt;/p&gt;
&lt;p&gt;マスクはテスラの2025年第3四半期決算説明会で&lt;a href="https://www.tomshardware.com/tech-industry/elon-musk-says-idling-tesla-cars-could-create-massive-100-million-vehicle-strong-computer-for-ai-bored-vehicles-could-offer-100-gigawatts-of-distributed-compute-power"&gt;このアイデアを提案した&lt;/a&gt;：1kWの推論能力を持つ車両が1億台あれば、それは100ギガワットの分散コンピューティングになる。冷却と電力変換はすでに車両に組み込まれている。データセンターの新規構築は不要だ。&lt;/p&gt;
&lt;h2 id="2台のコンピューター1台ではなく"&gt;2台のコンピューター、1台ではなく&lt;/h2&gt;
&lt;p&gt;ほとんどの人はテスラに1台のコンピューターが搭載されていると思っている。実際には2台ある。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AIチップ&lt;/strong&gt;（AI3/AI4/AI5）が推論アクセラレーターだ——ニューラルネットワークの順伝播専用に設計されている。これが脳だ。何をすべきかを決定するエージェントモデルを実行する。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;インフォテインメントシステム&lt;/strong&gt;は&lt;a href="https://videocardz.com/newz/tesla-car-computer-features-zen-ryzen-embedded-apu-and-discrete-navi-23-gpu"&gt;フルスペックのAMD Ryzenワークステーション&lt;/a&gt;だ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AMD Ryzen Embedded、4コア Zen+ 3.8 GHz&lt;/li&gt;
&lt;li&gt;8 GB RAM（Model 3/Y）または16 GB（Model S/X）&lt;/li&gt;
&lt;li&gt;AMD Navi 23 GPU（RDNA 2）——10 TFLOPS、PS5と同じアーキテクチャファミリー&lt;/li&gt;
&lt;li&gt;128〜256 GB ストレージ&lt;/li&gt;
&lt;li&gt;水冷式&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これはカーステレオではない。ディスクリートGPUを備えた水冷式Linuxマシンだ。テスラがNavi 23を搭載したのは、センターディスプレイでCyberpunk 2077をプレイできるようにするためだ。しかし、車が駐車されていて誰もゲームをしていないとき、それはアイドル状態のコンピューティングリソースだ。&lt;/p&gt;
&lt;p&gt;エージェントはクラウドVMを必要としない。車そのものがサーバーだ。AIチップがモデルを実行する。AMDシステムがコンテナ内でヘッドレスブラウザを実行する——Gmail、Googleスプレッドシート、Slack、エージェントが作業しているものなど何でも。水冷式冷却が、サーマルスロットリングなしに終夜の継続的な作業負荷を処理する。&lt;/p&gt;
&lt;p&gt;車両から出るのは、WebアプリへのHTTPSトラフィックだけだ——メールを確認するときにノートパソコンが生成するのと同じトラフィック。あなたのデータはテスラやxAIのサーバーを通過しない。推論はローカルで行われる。ワークスペースもローカルだ。&lt;/p&gt;
&lt;h2 id="アーキテクチャシステム1とシステム2"&gt;アーキテクチャ：システム1とシステム2&lt;/h2&gt;
&lt;p&gt;Macrohardは推論を2つのレイヤーに分割する：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;システム1（テスラのAIチップ）&lt;/strong&gt; ——高速でリアクティブな処理。車載モデルがリアルタイムの画面監視、マウス移動、キーボード入力を担当する。これが直感的なレイヤー——パターンマッチング、視覚的解析、即時応答だ。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;システム2（xAIのGrok）&lt;/strong&gt; ——高レベルの推論。計画立案、多段階の意思決定、文脈の理解。タスクがより深い思考を必要とする場合、xAIのクラウドで実行される。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;車がローカルで安価で高速な推論を処理する。高価な推論はクラウドで行われる。これはFSDを機能させるのと同じハイブリッドアーキテクチャだ——車がカメラ映像をミリ秒の遅延でローカル処理しながら、複雑なルート計画はネットワークに委ねることができる。&lt;/p&gt;
&lt;p&gt;コンピューター使用では、エージェントが画面の状態を追跡してローカルで日常的な操作を処理しながら、「この請求書を承認すべきか」や「このメールにどう返信すべきか」といった判断はGrokに委ねることができる。&lt;/p&gt;
&lt;h2 id="チャットボットではないワーカーだ"&gt;チャットボットではない。ワーカーだ。&lt;/h2&gt;
&lt;p&gt;重要な違いは、このシステムが何をするかだ。質問に答えるのではない。タスクを実行するのだ。&lt;/p&gt;
&lt;p&gt;テスラが駐車されているとき、Digital Optimusは以下のことができる：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;メールを処理して返信を下書きする&lt;/li&gt;
&lt;li&gt;スプレッドシートに入力する&lt;/li&gt;
&lt;li&gt;Webアプリケーションを操作する&lt;/li&gt;
&lt;li&gt;多段階のワークフローを完了する&lt;/li&gt;
&lt;li&gt;繰り返しデータ入力を処理する&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;各車がオーナーのタスクを独立して実行する。1回の推論呼び出しを複数の車両に分散させる必要はない——コンピューター使用は自明な並列化が可能だ。1台の車、1つのエージェント、1つのタスク。スケールはインターコネクト帯域幅ではなく、フリートサイズから生まれる。&lt;/p&gt;
&lt;p&gt;これが重要なのは、コンピューター使用の遅延許容度が大きいからだ。フォーム入力エージェントは1アクションあたり30秒かかっても有用だ。リアルタイムの応答を待っているのではなく——眠っている間に実行する作業を委任しているのだ。&lt;/p&gt;
&lt;h2 id="実際の使い勝手"&gt;実際の使い勝手&lt;/h2&gt;
&lt;p&gt;アーキテクチャ図は忘れよう。日常的な体験はこうなる。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;テスラアプリがコントロールプレーンだ。&lt;/strong&gt; 充電、気候、セントリーモードの既存コントロールの隣に「エージェント」タブが表示される。それを使って：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;タスクをキューに追加&lt;/strong&gt; ——「受信トレイを処理して」、「先週の領収書を照合して」、または「毎朝6時にメールを仕分けする」といった定期的なルール&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;アカウントを接続&lt;/strong&gt; ——Gmail、Googleドライブ、Microsoft 365、SlackのOAuthフロー&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;制約を設定&lt;/strong&gt; ——バッテリーの最低閾値、WiFiのみ、作業時間&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;結果を確認&lt;/strong&gt; ——エージェントが何をしたか確認し、アクションを承認または拒否する&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;あなたはベッドに横になっている。テスラアプリを開いて「先週の出張の経費報告書を提出して」と入力し、送信して眠りにつく。車はガレージに駐車されており、WiFiに接続され、バッテリーは80%だ。タスクを受け取る。&lt;/p&gt;</description></item><item><title>CIパイプラインステージとしてのビジュアルQA</title><link>https://granda.org/ja/2026/02/06/ci%E3%83%91%E3%82%A4%E3%83%97%E3%83%A9%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%86%E3%83%BC%E3%82%B8%E3%81%A8%E3%81%97%E3%81%A6%E3%81%AE%E3%83%93%E3%82%B8%E3%83%A5%E3%82%A2%E3%83%ABqa/</link><pubDate>Fri, 06 Feb 2026 00:00:00 +0000</pubDate><guid>https://granda.org/ja/2026/02/06/ci%E3%83%91%E3%82%A4%E3%83%97%E3%83%A9%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%86%E3%83%BC%E3%82%B8%E3%81%A8%E3%81%97%E3%81%A6%E3%81%AE%E3%83%93%E3%82%B8%E3%83%A5%E3%82%A2%E3%83%ABqa/</guid><description>&lt;p&gt;先月PRをマージした。コードレビューは問題なかった。テストも通った。それから携帯電話でサイトを開くと、サイドバーが完全に壊れていた。&lt;/p&gt;
&lt;p&gt;修正は些細なものだった—メディアクエリの欠落。モバイルビューを実際に見れば、バグは明らかだった。誰も見なかった。&lt;/p&gt;
&lt;p&gt;だから見るパイプラインステージを追加した。&lt;/p&gt;
&lt;p&gt;GitHubイシューを開いて、こう書く:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;クライアントを追加するための手動入力オプションを実装。クリックすると、新しいクライアントを作成するフォームを含む幅広いスライドオーバードロワーが開く。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;1つのコミット後、すべてのビューポートで各状態が機能することを証明する30枚以上のスクリーンショットとともにPRが届く。手動テストはゼロ。唯一の労力は機能説明を書くことだった。&lt;/p&gt;
&lt;h2 id="コンセプト"&gt;コンセプト&lt;/h2&gt;
&lt;p&gt;PRへのプッシュごとに、GitHub Actionsワークフローが:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;PRブランチからDocker Composeスタック(Django + Postgres)を起動&lt;/li&gt;
&lt;li&gt;マイグレーションを実行し、テストユーザーをシード&lt;/li&gt;
&lt;li&gt;ローカルURLをPlaywright MCP(ヘッドレスChromium)を使用したClaude Codeに渡す&lt;/li&gt;
&lt;li&gt;PR diffに基づいて対話要素を実行&lt;/li&gt;
&lt;li&gt;3つのビューポートで各状態をスクリーンショット&lt;/li&gt;
&lt;li&gt;結果をPRコメントとして投稿&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Claude Codeがブラウザを制御する。Docker Composeがアプリを提供する。GitHub Actionsがそれらを結びつける。レビュアーはローカルで何も実行せずに機能の証明を見る。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-mermaid" data-lang="mermaid"&gt;%%{init: {&amp;#34;flowchart&amp;#34;: {&amp;#34;subGraphTitleMargin&amp;#34;: {&amp;#34;top&amp;#34;: 3, &amp;#34;bottom&amp;#34;: 10}}} }%%
graph TD
 A[&amp;#34;PRプッシュ&amp;#34;] --&amp;gt; B

 subgraph GHA[&amp;#34;GitHub Actions Runner&amp;#34;]
 B[&amp;#34;Checkout + Docker Compose&amp;#34;] --&amp;gt; C[&amp;#34;マイグレーション + シードデータ&amp;#34;]
 C --&amp;gt; Agent

 subgraph Agent[&amp;#34;Claude Code + Playwright&amp;#34;]
 direction LR
 D[&amp;#34;PR Diffを読む&amp;#34;] --&amp;gt; E[&amp;#34;ファイル → URLをマップ&amp;#34;]
 E --&amp;gt; F[&amp;#34;ログイン + ナビゲート&amp;#34;]
 F --&amp;gt; G[&amp;#34;スクリーンショット ×3ビューポート&amp;#34;]
 end
 end

 Agent --&amp;gt; H[&amp;#34;PRコメント&amp;#34;]

 style GHA fill:transparent,stroke:#888
 style Agent fill:transparent,stroke:#888
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;ワークフロー自体は単純:&lt;/p&gt;</description></item><item><title>Agent Traceは誰のためのものか?</title><link>https://granda.org/ja/2026/01/30/agent-trace%E3%81%AF%E8%AA%B0%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%82%82%E3%81%AE%E3%81%8B/</link><pubDate>Fri, 30 Jan 2026 00:00:00 +0000</pubDate><guid>https://granda.org/ja/2026/01/30/agent-trace%E3%81%AF%E8%AA%B0%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%82%82%E3%81%AE%E3%81%8B/</guid><description>&lt;p&gt;Cursorは&lt;a href="https://github.com/cursor/agent-trace"&gt;Agent Trace&lt;/a&gt;をリリースした。これは、リポジトリ内のどのコードがLLMによって書かれたかを追跡するためのオープン仕様である。モデル、ツール、会話、正確な行範囲を記録し、すべてがプロジェクト内のJSONLファイルに追加される。&lt;/p&gt;
&lt;p&gt;提案内容:「エージェントがより多くのコードを書くにつれて、AIと人間のどちらから来たかを理解することが重要になる。」&lt;/p&gt;
&lt;p&gt;私は仕様とリファレンス実装を読むのに時間を費やした。エンジニアリングは堅実だ。クリーンなスキーマ、思慮深い拡張性、良好なパートナーリスト(Amp、Amplitude、Cloudflare、Cognition、Google、Vercel)。しかし、私は一つの疑問に何度も戻った:このデータで何を&lt;em&gt;する&lt;/em&gt;のか?&lt;/p&gt;
&lt;h2 id="何を捕捉するか"&gt;何を捕捉するか&lt;/h2&gt;
&lt;p&gt;LLMがファイルを編集するたびに、フックが起動してトレースを記録する:どのモデル、どのツール、どの行、どの会話。リファレンス実装は、CursorとClaude Codeの両方からのイベントを処理する:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// リファレンスフックから — イベントはstdinを通じて流れ込む
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;appendTrace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;createTrace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ai&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file_path&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;model&lt;/span&gt;: &lt;span class="kt"&gt;input.model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;rangePositions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;transcript&lt;/span&gt;: &lt;span class="kt"&gt;input.transcript_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;conversation_id&lt;/span&gt;: &lt;span class="kt"&gt;input.conversation_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;generation_id&lt;/span&gt;: &lt;span class="kt"&gt;input.generation_id&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;仕様は4つの貢献者タイプ(&lt;code&gt;human&lt;/code&gt;、&lt;code&gt;ai&lt;/code&gt;、&lt;code&gt;mixed&lt;/code&gt;、&lt;code&gt;unknown&lt;/code&gt;)を定義し、コンテンツハッシュによる行レベルの帰属をサポートして、移動するコードを追跡する。ベンダー中立で、VCSに依存せず、名前空間付きメタデータを介して拡張可能である。&lt;/p&gt;
&lt;p&gt;データフォーマットとしては、よく設計されている。問題は、それが何を可能にするかである。&lt;/p&gt;
&lt;h2 id="帰属の課題"&gt;帰属の課題&lt;/h2&gt;
&lt;p&gt;仕様は著者権を分類としてモデル化している。しかし、LLM支援コーディングは会話である。あなたは欲しいものを説明する。LLMが何かを生成する。あなたはその半分を編集し、関数を却下し、修正を求め、2回目の試行を受け入れ、その後手動でエッジケースを修正する。後で、別のLLMがブロック全体をリファクタリングする。&lt;/p&gt;
&lt;p&gt;そのコードを誰が書いたのか?人間とLLMの著者権の境界は曖昧であり、ますます曖昧になっている。ほとんどの実際のコードは&lt;code&gt;mixed&lt;/code&gt;になり、ほぼすべてが&lt;code&gt;mixed&lt;/code&gt;であれば、分類はあまり意味をなさない。&lt;/p&gt;
&lt;p&gt;行レベルの帰属には賞味期限の問題もある。トレースは「Claudeがコミット&lt;code&gt;abc123&lt;/code&gt;で10-50行を書いた」と言う。2つのコミット後、誰かがそのブロックを再フォーマットするか、そこから関数を抽出する。仕様の答えは&lt;code&gt;git blame&lt;/code&gt;を通じてチェーンすることであり、コンテンツハッシュは移動するコードの追跡に役立つ。しかし、リベースやスカッシュマージのあるワークフローでは、チェーンが壊れる。これらは難しい問題であり、初期のRFCが表面化すべき種類のものだ。&lt;/p&gt;
&lt;h2 id="欠けているアクション"&gt;欠けているアクション&lt;/h2&gt;
&lt;p&gt;仕様は明示的に明白な用途を否認している:コード所有権のためではない、品質評価のためではない、トレーニングデータの出所のためではない。「透明性」と言っている。しかし、透明性は手段であり、目的ではない。&lt;/p&gt;
&lt;p&gt;コードがレビューとテストを通過すれば、LLMが書いたからといって何が変わるのか?バグがあれば、とにかく修正する。仕様は帰属を具体的なアクションに結びつけることは決してない。データは入るが、答えを得るための定義された方法がない。それがギャップだ — フォーマットではなく、ユースケースである。&lt;/p&gt;
&lt;h2 id="興味深くなるところ"&gt;興味深くなるところ&lt;/h2&gt;
&lt;p&gt;これは、仕様がまだ言っていないとしても、Agent Traceが実際に指し示していると私が考えるものだ。&lt;/p&gt;
&lt;p&gt;すべてのLLM生成関数の背後には、推論トークン、間違った方向、リトライ、コンテキストスイッチ、ツール呼び出しがある。エージェントは単にコードを生成するだけでなく、そこに到達するための&lt;em&gt;プロセス&lt;/em&gt;を経る。ファイルを読み、インターフェースを誤解し、バックトラックし、別のアプローチを試し、テストを実行し、失敗を修正し、解決策に到達する。そのプロセスは最終的な差分では見えない。&lt;/p&gt;
&lt;p&gt;フックはすでに帰属以上のものを捕捉している。入力サーフェスを見てみよう:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;HookInput&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;hook_event_name&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;model?&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;transcript_path?&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;conversation_id?&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;generation_id?&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;session_id?&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;file_path?&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;edits?&lt;/span&gt;: &lt;span class="kt"&gt;FileEdit&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;command?&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;duration?&lt;/span&gt;: &lt;span class="kt"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;is_background_agent?&lt;/span&gt;: &lt;span class="kt"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;composer_mode?&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tool_name?&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tool_input&lt;/span&gt;&lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;file_path?&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;new_string?&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;old_string?&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;command?&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tool_use_id?&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;モデル、セッション、会話、ツール、コマンド、期間、バックグラウンドエージェントかどうか、コンポーザーモード、その入力を持つすべてのツール呼び出し。これは単なる帰属データではない。これはプロセスデータである。そして、プロセスデータこそが真の価値が存在する場所である:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;評価。&lt;/strong&gt; どのモデルがどのパターンで苦労するか?1回の試行で済んだ関数は、12回のリトライを要した関数とは異なる — 出力が同一であっても。「誰が書いたか」ではなく「生成するのがどれほど困難だったか」。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;エージェントネイティブなコードベース。&lt;/strong&gt; エージェントがモジュールで一貫して苦労している場合(多くの間違った方向、高いリトライ率、繰り返されるコンテキスト混乱) — それは、コードがエージェントの動作方法に対して構造化されていないというシグナルである。明確性、より良いインターフェース、より明示的な契約のためにリファクタリングできる。トレースデータは、コードベースがLLMコラボレーションに敵対的である場所のマップになる。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;プロセス最適化。&lt;/strong&gt; どのツール構成がより良い初回試行コードを生成するか?どのプロンプティングパターンがバックトラックを減らすか?行の帰属からこれらに答えることはできない。目的地ではなく、旅が必要である。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="正しい問い"&gt;正しい問い&lt;/h2&gt;
&lt;p&gt;Agent Traceは初期段階である。帰属モデリング、範囲の耐久性、クエリセマンティクスに関する実際の課題を持つRFCである。しかし、直感は正しい — LLMがより多くのコードを書くにつれて、それがどのように起こるかについての構造化データが必要である。&lt;/p&gt;
&lt;p&gt;この仕様の最も有用なバージョンは、「LLMが何を書いたか?」ではなく「LLMがどのようにそこに到達したか?」かもしれない。行レベルの台帳は出発点である。プロセストレース — 推論、反復、解決策に到達するコスト — こそが、これがチームがLLMでより良いコードを書くために実際に使用するものになる場所である。&lt;/p&gt;</description></item><item><title>怠惰な開発者のためのリッチリンク</title><link>https://granda.org/ja/2026/01/10/%E6%80%A0%E6%83%B0%E3%81%AA%E9%96%8B%E7%99%BA%E8%80%85%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%83%AA%E3%83%83%E3%83%81%E3%83%AA%E3%83%B3%E3%82%AF/</link><pubDate>Sat, 10 Jan 2026 00:00:00 +0000</pubDate><guid>https://granda.org/ja/2026/01/10/%E6%80%A0%E6%83%B0%E3%81%AA%E9%96%8B%E7%99%BA%E8%80%85%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%83%AA%E3%83%83%E3%83%81%E3%83%AA%E3%83%B3%E3%82%AF/</guid><description>&lt;p&gt;ブログのリンクをTwitterやSlackで共有すると、プレーンテキストとして表示されます。プレビュー画像はありません。&lt;a href="https://granda.org/en/2026/01/02/claude-code-on-the-go/"&gt;granda.org/en/2026/01/02/claude-code-on-the-go/&lt;/a&gt;のようなURLだけです。&lt;/p&gt;
&lt;p&gt;Open Graph画像が必要でした。標準的なアプローチ:各投稿に対して手動で1200x630の画像を作成する。それは面倒です。Claudeに自動化を依頼しました。&lt;/p&gt;
&lt;div class="desktop-only"&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-mermaid" data-lang="mermaid"&gt;flowchart LR
 Push[git push] --&amp;gt; GHA[GitHub Actions]
 GHA --&amp;gt; Hugo[Hugo Server]
 GHA --&amp;gt; PW[Playwright]
 PW --&amp;gt;|screenshot| Hugo
 PW --&amp;gt; IMG[OG Image]
 IMG --&amp;gt; Commit[git commit]
 Commit --&amp;gt; Deploy[Deploy]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="mobile-only"&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-mermaid" data-lang="mermaid"&gt;flowchart TB
 Push[git push] --&amp;gt; GHA[GitHub Actions]
 GHA --&amp;gt; Hugo[Hugo Server]
 GHA --&amp;gt; PW[Playwright]
 PW --&amp;gt;|screenshot| Hugo
 PW --&amp;gt; IMG[OG Image]
 IMG --&amp;gt; Commit[git commit]
 Commit --&amp;gt; Deploy[Deploy]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="セットアップ"&gt;セットアップ&lt;/h2&gt;
&lt;p&gt;Claudeに問題を説明しました:投稿にはソーシャルプレビュー画像が必要ですが、手動で作成したくありません。記事の内容をスクリーンショットし、OG画像として保存し、フロントマターを自動的に更新します。&lt;/p&gt;
&lt;h2 id="claudeが構築したもの"&gt;Claudeが構築したもの&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;コンポーネント&lt;/th&gt;
 &lt;th&gt;目的&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;generate-og-image.js&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;投稿のスクリーンショットを撮るPlaywrightスクリプト&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;generate-og-images.yml&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;投稿の変更時にトリガーされるGitHub Action&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;baseof.html&lt;/code&gt;の変更&lt;/td&gt;
 &lt;td&gt;条件付きog:imageメタタグ&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;PlaywrightスクリプトはヘッドレスのChromeを起動し、投稿に移動し、ライトモードを強制し、ヘッダーとフッターを非表示にし、1200x630でスクリーンショットを撮ります:&lt;/p&gt;</description></item><item><title>配信停止</title><link>https://granda.org/ja/unsubscribe/</link><pubDate>Sat, 10 Jan 2026 00:00:00 +0000</pubDate><guid>https://granda.org/ja/unsubscribe/</guid><description>&lt;p id="unsubscribe-message"&gt;処理中...&lt;/p&gt;
&lt;script&gt;
(function() {
 const params = new URLSearchParams(window.location.search);
 const msg = document.getElementById('unsubscribe-message');

 if (params.get('success') === 'true') {
 msg.textContent = 'ニュースレターの配信を停止しました。';
 } else if (params.get('error') === 'missing') {
 msg.textContent = 'エラー: 配信停止トークンが提供されていません。';
 } else if (params.get('error') === 'invalid') {
 msg.textContent = 'エラー: 無効な配信停止リンクです。';
 } else {
 msg.textContent = 'エラー: 不明なエラーが発生しました。';
 }
})();
&lt;/script&gt;</description></item><item><title>私のQAエンジニアはLLMです</title><link>https://granda.org/ja/2026/01/09/%E7%A7%81%E3%81%AEqa%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AFllm%E3%81%A7%E3%81%99/</link><pubDate>Fri, 09 Jan 2026 00:00:00 +0000</pubDate><guid>https://granda.org/ja/2026/01/09/%E7%A7%81%E3%81%AEqa%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AFllm%E3%81%A7%E3%81%99/</guid><description>&lt;p&gt;Claudeはボタンをクリックできます。&lt;/p&gt;
&lt;p&gt;些細なことのように聞こえますが、UIの構築方法を変えます。Playwright MCPを使うと、Claudeは単にコードを書くだけでなく、ブラウザを開き、localhostに移動し、実際に動作することを検証します。コードレビューで見逃すバグを発見します。&lt;/p&gt;
&lt;h2 id="セットアップ"&gt;セットアップ&lt;/h2&gt;
&lt;p&gt;Playwright MCPはClaudeにブラウザ自動化を提供します。ヘッドレスChromiumで実行しています:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;mcpServers&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;playwright&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;npx&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;@anthropic-ai/mcp-server-playwright&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;--headless&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これでClaudeはナビゲート、クリック、タイプ、スクリーンショットができます。ユーザーが見るものを見ます。&lt;/p&gt;
&lt;div class="desktop-only"&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-mermaid" data-lang="mermaid"&gt;flowchart LR
 Claude([Claude Code]) --&amp;gt;|browser_snapshot| PW[Playwright MCP]
 PW --&amp;gt; Browser[Headless Chrome]
 Browser --&amp;gt; App[localhost:1313]
 Browser -.-&amp;gt;|screenshot| Issue[(GitHub Issue)]
 Issue -.-&amp;gt;|visual history| PR[Pull Request]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="mobile-only"&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-mermaid" data-lang="mermaid"&gt;flowchart TB
 Claude([Claude Code]) --&amp;gt;|browser_snapshot| PW[Playwright MCP]
 PW --&amp;gt; Browser[Headless Chrome]
 Browser --&amp;gt; App[localhost:1313]
 Browser -.-&amp;gt;|screenshot| Issue[(GitHub Issue)]
 Issue -.-&amp;gt;|visual history| PR[Pull Request]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;フロー: Claude Code → Playwright MCP → ブラウザ → スクリーンショット → GitHub Issues → PR&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Claudeで独自のニュースレターを作成</title><link>https://granda.org/ja/2026/01/07/claude%E3%81%A7%E7%8B%AC%E8%87%AA%E3%81%AE%E3%83%8B%E3%83%A5%E3%83%BC%E3%82%B9%E3%83%AC%E3%82%BF%E3%83%BC%E3%82%92%E4%BD%9C%E6%88%90/</link><pubDate>Wed, 07 Jan 2026 00:00:00 +0000</pubDate><guid>https://granda.org/ja/2026/01/07/claude%E3%81%A7%E7%8B%AC%E8%87%AA%E3%81%AE%E3%83%8B%E3%83%A5%E3%83%BC%E3%82%B9%E3%83%AC%E3%82%BF%E3%83%BC%E3%82%92%E4%BD%9C%E6%88%90/</guid><description>&lt;p&gt;Hacker Newsのトラフィック急増の2日目。4万人の訪問者、彼らに再びリーチする方法がない。ニュースレターの登録フォームが必要だった。&lt;/p&gt;
&lt;p&gt;Buttondown、Beehiiv、Substack、ConvertKitを調べた。すべて過剰だった。私はメールアドレスを収集するだけでよかった。キャンペーン、分析、購読者管理は必要なかった。そして、自分のデータを所有したかった。&lt;/p&gt;
&lt;p&gt;そこで、Claudeに構築を依頼した。&lt;/p&gt;
&lt;div class="desktop-only"&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-mermaid" data-lang="mermaid"&gt;flowchart LR
 User([User]) --&amp;gt; Form[Newsletter Form]
 Form --&amp;gt;|POST /api/subscribe| Worker[Cloudflare Worker]
 Worker --&amp;gt; KV[(Cloudflare KV)]
 KV -.-&amp;gt;|Daily sync| GHA[GitHub Actions]
 GHA -.-&amp;gt; Repo[(subscribers.jsonl)]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="mobile-only"&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-mermaid" data-lang="mermaid"&gt;flowchart TB
 User([User]) --&amp;gt; Form[Newsletter Form]
 Form --&amp;gt;|POST /api/subscribe| Worker[Cloudflare Worker]
 Worker --&amp;gt; KV[(Cloudflare KV)]
 KV -.-&amp;gt;|Daily sync| GHA[GitHub Actions]
 GHA -.-&amp;gt; Repo[(subscribers.jsonl)]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="セットアップ"&gt;セットアップ&lt;/h2&gt;
&lt;p&gt;環境変数を介してCloudflare APIトークンをClaudeに渡し、欲しいものを説明した：メールアドレスを収集し、私が管理する場所に保存するフォーム。&lt;/p&gt;
&lt;p&gt;30分足らずで、動作するニュースレターができた。&lt;/p&gt;
&lt;h2 id="claudeが構築したもの"&gt;Claudeが構築したもの&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;コンポーネント&lt;/th&gt;
 &lt;th&gt;技術&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;フォーム&lt;/td&gt;
 &lt;td&gt;HTML + vanilla JS&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;バックエンド&lt;/td&gt;
 &lt;td&gt;Cloudflare Worker&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;ストレージ&lt;/td&gt;
 &lt;td&gt;Cloudflare KV&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;同期&lt;/td&gt;
 &lt;td&gt;GitHub Actions&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;フォームは&lt;code&gt;/api/subscribe&lt;/code&gt;にポストするHugo partialである：&lt;/p&gt;</description></item><item><title>外出先でのClaude Code</title><link>https://granda.org/ja/2026/01/02/%E5%A4%96%E5%87%BA%E5%85%88%E3%81%A7%E3%81%AEclaude-code/</link><pubDate>Fri, 02 Jan 2026 00:00:00 +0000</pubDate><guid>https://granda.org/ja/2026/01/02/%E5%A4%96%E5%87%BA%E5%85%88%E3%81%A7%E3%81%AEclaude-code/</guid><description>&lt;p&gt;私は携帯電話から6つのClaude Codeエージェントを並列で実行しています。ノートパソコンもデスクトップもなく、iOSのTermiusとクラウドVMだけです。&lt;/p&gt;
&lt;h2 id="セットアップ"&gt;セットアップ&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-mermaid" data-lang="mermaid"&gt;flowchart LR
 A[Phone] --&amp;gt;|Termius + mosh| B[Tailscale VPN]
 B --&amp;gt; C[Vultr VM]
 C --&amp;gt; D[Claude Code]
 D --&amp;gt;|PreToolUse hook| E[Poke webhook]
 E --&amp;gt;|Push notification| A
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;サイクルは、タスクを開始し、電話をポケットに入れ、Claudeが入力を必要とするときに通知を受け取ることです。どこからでも非同期開発。&lt;/p&gt;
&lt;h2 id="インフラストラクチャ"&gt;インフラストラクチャ&lt;/h2&gt;
&lt;p&gt;シリコンバレーのVultr VM:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Spec&lt;/th&gt;
 &lt;th&gt;Value&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Instance&lt;/td&gt;
 &lt;td&gt;vhf-8c-32gb&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Cost&lt;/td&gt;
 &lt;td&gt;$0.29/時間 (稼働時は~$7/日)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Access&lt;/td&gt;
 &lt;td&gt;Tailscaleのみ (公開SSHなし)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;作業時のみ支払います。2つのスクリプトがライフサイクルを管理します:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vm-start &lt;span class="c1"&gt;# Start VM, wait for Tailscale, connect via mosh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vm-stop &lt;span class="c1"&gt;# Halt VM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;また、Vultr APIを直接呼び出すiOS Shortcutも持っています。Termiusを開く前に、電話からVMを起動します。&lt;/p&gt;
&lt;p&gt;VMの公開IPにはSSHリスナーがありません。すべてのアクセスはTailscaleのプライベートネットワークを経由します。多層防御: クラウドファイアウォールはTailscale調整以外のすべてをブロック、バックアップとしてのローカルnftables、念のためfail2ban。&lt;/p&gt;
&lt;h2 id="モバイルターミナル"&gt;モバイルターミナル&lt;/h2&gt;
&lt;p&gt;TermiusはiOS/AndroidでSSHとmoshを処理します。moshが鍵です。ネットワークの移行に耐えられます。WiFiからセルラーに切り替え、デッドゾーンを歩き、電話をスリープにします。接続は持続します。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mosh --ssh&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ssh -p 47892&amp;#34;&lt;/span&gt; mgranda@100.100.100.100
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;1つの注意点: moshはSSHエージェントを転送しません。GitHub認証が必要なgit操作には、tmux内で通常のSSHを使用します。&lt;/p&gt;
&lt;h2 id="セッション永続性"&gt;セッション永続性&lt;/h2&gt;
&lt;p&gt;シェルはログイン時に自動的にtmuxにアタッチします。Termiusを閉じて、数時間後に再度開いても、すべてがそこにあります。&lt;/p&gt;</description></item><item><title>AIに任せる</title><link>https://granda.org/ja/2025/12/28/ai%E3%81%AB%E4%BB%BB%E3%81%9B%E3%82%8B/</link><pubDate>Sun, 28 Dec 2025 00:00:00 +0000</pubDate><guid>https://granda.org/ja/2025/12/28/ai%E3%81%AB%E4%BB%BB%E3%81%9B%E3%82%8B/</guid><description>&lt;p&gt;開発サーバーが必要だった：SSHアクセスと開発ツールがインストールされたVM。Claude Codeに何が欲しいか説明して、セットアップを任せた。&lt;/p&gt;
&lt;h2 id="プロンプト"&gt;プロンプト&lt;/h2&gt;
&lt;p&gt;8コアと32GBのRAMを持つVultr VMを要求した。Tailscale経由でのみアクセス可能で、ネットワーク切断に耐える永続セッション付き。&lt;/p&gt;
&lt;h2 id="claude-codeが構築したもの"&gt;Claude Codeが構築したもの&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;1. Vultr API経由でVMをプロビジョニング&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;8コア/32GBのUbuntuインスタンスを作成し、IPを待ってから、rootとしてSSH接続した。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. SSHを強化&lt;/strong&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-conf" data-lang="conf"&gt;Port 49152 # ランダムな高ポート
PermitRootLogin no
PasswordAuthentication no
ListenAddress 100.x.x.x # Tailscaleインターフェースのみ
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;鍵ベースの認証のみ、Tailscaleインターフェースのみでリッスン。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 3層のファイアウォールを設定&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;UFW&lt;/strong&gt;: Tailscaleサブネット以外のすべての着信を拒否&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fail2ban&lt;/strong&gt;: ログイン試行失敗後にIPを自動ban&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vultrファイアウォール&lt;/strong&gt;: ハイパーバイザーレベルですべてをブロック&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;4. SSHを有効にしてTailscaleをインストール&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -fsSL https://tailscale.com/install.sh &lt;span class="p"&gt;|&lt;/span&gt; sh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;tailscale up --ssh --authkey&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$TAILSCALE_KEY&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;これにより、OpenSSHとは独立したTailscaleのビルトインSSHサーバー経由で2つ目のSSHパスが作成される。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. 開発スタックをインストール&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Node.js（nvm経由）、Python（pyenv経由）、Docker、一般的なツール。Dockerをsudoなしで実行できるように設定。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6. tmuxで永続セッションを設定&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;既存のセッションに自動的に再接続する起動スクリプトで、ネットワーク切断が実行中のプロセスを終了しないようにした。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;7. ローカル管理スクリプトを作成&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;私のラップトップに、Vultr API経由でVMを起動・停止する&lt;code&gt;dev-start&lt;/code&gt;と&lt;code&gt;dev-stop&lt;/code&gt;スクリプトを作成。&lt;/p&gt;
&lt;h2 id="ロックアウト"&gt;ロックアウト&lt;/h2&gt;
&lt;p&gt;終了後、Claude Codeはrootログインが無効になっていることを確認するため、rootとしてSSH接続を試みた。ログインは失敗した。fail2banが失敗した試行に気づき、私たちをbanした。&lt;/p&gt;
&lt;p&gt;Claude CodeはセカンダリパスとしてTailscale SSHを設定していた。&lt;code&gt;tailscale ssh&lt;/code&gt;を使って戻り、以下を実行した：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fail2ban-client &lt;span class="nb"&gt;set&lt;/span&gt; sshd unbanip 100.x.x.x
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="セットアップ"&gt;セットアップ&lt;/h2&gt;
&lt;p&gt;必要なもの：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Claude Code（またはツール使用可能な同様のAI）&lt;/li&gt;
&lt;li&gt;クラウドプロバイダーアカウント（Vultr、DigitalOcean、AWSなど）&lt;/li&gt;
&lt;li&gt;Tailscaleアカウント&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;APIキーを環境変数として保存し、名前で参照する（例：&lt;code&gt;$VULTR_API_KEY&lt;/code&gt;）ことで、シークレットが会話に現れないようにする。&lt;/p&gt;</description></item><item><title>ClaudeとGitHub Actionsによるブログの自動翻訳</title><link>https://granda.org/ja/2025/12/23/claude%E3%81%A8github-actions%E3%81%AB%E3%82%88%E3%82%8B%E3%83%96%E3%83%AD%E3%82%B0%E3%81%AE%E8%87%AA%E5%8B%95%E7%BF%BB%E8%A8%B3/</link><pubDate>Tue, 23 Dec 2025 00:00:00 +0000</pubDate><guid>https://granda.org/ja/2025/12/23/claude%E3%81%A8github-actions%E3%81%AB%E3%82%88%E3%82%8B%E3%83%96%E3%83%AD%E3%82%B0%E3%81%AE%E8%87%AA%E5%8B%95%E7%BF%BB%E8%A8%B3/</guid><description>&lt;p&gt;私が書くすべての記事は自動的に翻訳されます。Claudeが翻訳を処理し、結果をmainにコミットし、翻訳版はオリジナルと一緒にデプロイされます。&lt;/p&gt;
&lt;h2 id="フロー"&gt;フロー&lt;/h2&gt;
&lt;p&gt;翻訳ワークフローは、英語コンテンツがmainにマージされるとGitHub Actionsで実行されます：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;push&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="l"&gt;main]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;content/**/*.en.md&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-mermaid" data-lang="mermaid"&gt;flowchart LR
 B[mainにマージ] --&amp;gt; C[翻訳が生成される]
 C --&amp;gt; D[mainにコミット]
 D --&amp;gt; E[全言語で本番デプロイ]
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="プロンプト"&gt;プロンプト&lt;/h2&gt;
&lt;p&gt;ワークフローは&lt;a href="https://github.com/anthropics/claude-code-action"&gt;claude-code-action&lt;/a&gt;を使用します：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;For each .en.md file that was added or modified:
1. Read the English content
2. Create translations for these languages: es, nl, de, it, fr, ja, zh, ru, hi
3. Save each translation as filename.{lang}.md (e.g., hello-world.es.md)
4. Preserve the frontmatter structure exactly, but translate the title
5. Translate the body content naturally
6. Keep code blocks, URLs, file paths, and technical terms unchanged
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;1つのプロンプトで9言語すべてを処理します。「自然に翻訳する」は「このテキストを翻訳する」よりも流暢な出力を生成します。コードブロックと技術用語は英語のままです。&lt;/p&gt;</description></item><item><title>このサイトについて</title><link>https://granda.org/ja/authorship/</link><pubDate>Mon, 22 Dec 2025 00:00:00 +0000</pubDate><guid>https://granda.org/ja/authorship/</guid><description>&lt;h2 id="概要"&gt;概要&lt;/h2&gt;
&lt;p&gt;この文書は、このブログで採用されている執筆方法論について説明します。&lt;/p&gt;
&lt;h2 id="1-はじめに"&gt;1. はじめに&lt;/h2&gt;
&lt;p&gt;このブログは、主にLarge Language Models(LLMs)の支援を受けて生成されています。著者は方向性、編集、品質管理を提供し、機械は初稿と翻訳を提供します。&lt;/p&gt;
&lt;h2 id="2-根拠"&gt;2. 根拠&lt;/h2&gt;
&lt;p&gt;著者は、AIを活用したコンテンツ作成に関する透明性を信じています。使用しているツールを隠すのではなく、この開示は以下を目的としています:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;読者に適切な期待を設定すること&lt;/li&gt;
&lt;li&gt;AIコンテンツに関する正直な規範に貢献すること&lt;/li&gt;
&lt;li&gt;現代の執筆における協働的な性質を認めること&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="3-これが意味すること"&gt;3. これが意味すること&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;アイデア&lt;/strong&gt;: 人間が創出&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;構造&lt;/strong&gt;: 協働&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;文章&lt;/strong&gt;: 主にAIが生成し、人間がレビュー&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;翻訳&lt;/strong&gt;: 完全にAIが生成(人間によるレビューなし)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="4-品質保証"&gt;4. 品質保証&lt;/h2&gt;
&lt;p&gt;英語コンテンツは公開前に人間によるレビューを受けます。翻訳は自動的に生成されるため、エラーや不自然な表現が含まれる可能性があります。著者は最終的に公開される英語コンテンツについて責任を負います。&lt;/p&gt;
&lt;h2 id="5-お問い合わせ"&gt;5. お問い合わせ&lt;/h2&gt;
&lt;p&gt;このポリシーに関する質問や懸念は、著者にお寄せください。&lt;/p&gt;</description></item><item><title>概要</title><link>https://granda.org/ja/about/</link><pubDate>Mon, 22 Dec 2025 00:00:00 +0000</pubDate><guid>https://granda.org/ja/about/</guid><description>&lt;h2 id="要旨"&gt;要旨&lt;/h2&gt;
&lt;p&gt;本ドキュメントは、このブログの著者に関する背景情報を提供します。&lt;/p&gt;
&lt;h2 id="1-経歴"&gt;1. 経歴&lt;/h2&gt;
&lt;p&gt;15年の経験を持つソフトウェアエンジニアで、そのうち10年を実務で過ごしました。
専門分野は以下の通りです:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;分散システム&lt;/li&gt;
&lt;li&gt;バックエンド開発とインフラストラクチャ&lt;/li&gt;
&lt;li&gt;フルスタックおよびエンドツーエンドの製品開発&lt;/li&gt;
&lt;li&gt;ユーザーインターフェース設計&lt;/li&gt;
&lt;li&gt;安全で信頼性の高いシステムの構築&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="2-連絡先"&gt;2. 連絡先&lt;/h2&gt;
&lt;p&gt;業界の方々との交流を歓迎します:
&lt;a href="https://x.com/mtt"&gt;@mtt&lt;/a&gt;&lt;/p&gt;</description></item><item><title>こんにちは世界</title><link>https://granda.org/ja/2025/12/20/%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C/</link><pubDate>Sat, 20 Dec 2025 00:00:00 +0000</pubDate><guid>https://granda.org/ja/2025/12/20/%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E4%B8%96%E7%95%8C/</guid><description>&lt;p&gt;ブログへようこそ！これは私の最初の投稿です。&lt;/p&gt;
&lt;p&gt;ここではアイデア、メモ、興味深いことを共有していきます。&lt;/p&gt;</description></item></channel></rss>