ブログに戻る

Linearの代替: ローカルファーストのイシュートラッキングが想像以上に速い理由

Linearは速い。正当な評価だ。体感パフォーマンスに大きく投資しており、ほとんどのチームにとっては利用可能な最高のSaaSイシュートラッカーだ。しかし「最高のSaaS」には、一部の開発者が受け入れられない制約がある: データは他人のサーバーに存在し、ワークフローは彼らの意見に合わせて曲げられ、すべてのインタラクションにネットワークラウンドトリップのコストがかかる。

この記事はそうした壁にぶつかった開発者向けだ。1時間に50件のイシューを登録するAIエージェントフリートを管理しているかもしれない。エアギャップやオフラインファーストの環境で作業しているかもしれない。イシューにアクセスするのにログイン画面が挟まるのが嫌なだけかもしれない。すべてをローカルに保持するネイティブデスクトップイシュートラッカーBeadboxを構築しながら学んだことを共有する。

関心のあるセクションにジャンプ:

開発者がLinearの代替を探す理由

よくある回答は「Linearは押しつけがましい」だ。正しいが不正確だ。Linearは2週間のケイデンスで出荷するプロダクトチームを前提としたサイクル、チーム構造、ワークフロー状態を強制する。それに当てはまるならLinearは最適だ。AIエージェントをコーディネートするソロ開発者、非標準のイテレーションパターンを持つ研究チーム、Slackスレッドではなくgitコミットにイシューを紐付けたいDevOpsグループの場合、Linearの意見は摩擦になる。

より根本的な問題はアーキテクチャだ。Linearはクラウドファーストの SaaS製品だ。すべてのミューテーションが彼らのサーバーとの往復になる。すべてのクエリが彼らのアップタイムに依存する。イシューデータは彼らのデータベースに存在し、彼らのAPIを通じて、彼らの条件でクエリ可能だ。ほとんどのチームにとっては許容できるトレードオフだ。データ主権、オフラインアクセス、大規模データセットでのクエリ速度を重視する開発者にとっては受け入れがたい条件だ。

Beadboxがやらないこと

Beadboxの得意分野に入る前に、適切でないケースを説明する。このセクションをスキップしても助けにならない。ツールを導入した後にこれらの壁にぶつかるよりマシだ。

マルチユーザー権限やアクセス制御はない。 ユーザーアカウント、ロール、イシューごとの可視性制限はない。.beads/ディレクトリ(またはDoltサーバー)にファイルシステムアクセス権がある人は誰でもすべてを読み書きできる。誰が何を見られるかを制限する必要があるなら、今のBeadboxは合わない。

リアルタイムコラボレーションが限定的。 2人が同じイシューセットで作業できるが、コラボレーションモデルは(Gitと同じ)push/pullであり、ライブカーソルやプレゼンスインジケーターではない。サーバーモードではBeadboxが3〜5秒ごとに変更をポーリングする。エンベデッドモードではファイルシステムウォッチがより速く変更を検出する(サブセカンド)。ただし2つのプロセスから同じDoltデータベースへの同時書き込みはクラッシュする可能性がある。安全なパターンは: 一度に1つのライターにするか、Doltが同時実行を処理するサーバーモードを使用する。

Slack、GitHub、Figmaなど他のSaaSツールとのインテグレーションはない。 拡張ポイントはbd CLIとシェルスクリプトだ。「イシューがクローズされたらSlackメッセージをトリガー」というワークフローに依存しているなら、そのグルーコードは自分で構築する必要がある。

スケール上限は存在するが遠い。 10Kと20Kのイシューデータセットでテストしている(下記ベンチマーク参照)。問題なく処理できる。100K以上のイシューではストレステストを行っていない。年間数十万件のイシューを生成する大規模組織なら、まだ検証されていない領域だ。

非技術系ステークホルダーのアクセスがない。 Webポータル、ゲストビューアー、共有可能なダッシュボードURLはない。Beadboxはローカルデータベースを読むデスクトップアプリだ。自分のマシンを使わないPMに進捗を見せるには、画面共有かレポートを生成するbdスクリプトが必要だ。

Beadboxの仕組み(30秒版)

ベンチマークを理解するには、まずアーキテクチャを知る必要がある:

Beadboxアーキテクチャ: WebView、WebSocketサーバー、bd CLI、ローカルDoltデータベース、オプションのリモート同期を備えたTauriアプリ

エンベデッドモード: Doltデータベースはファイルシステム上の.beads/に存在する。サーバープロセスなし、デーモンなし。bd CLIが直接読み書きする。Beadboxは250msデバウンスのfs.watch()で変更を検出し、WebSocketでUIにブロードキャストする。ゼロセットアップのパスだ。

サーバーモード: dolt sql-serverプロセスが別途実行される(ローカルまたはLAN)。bd CLIがMySQLプロトコルで接続する。Beadboxはファイルシステムウォッチの代わりに3〜5秒ごとにサーバーをポーリングして変更を確認する。このモードは複数の同時ライターをサポートする。

GUIが実行するすべての操作はbd CLIを経由する。Beadboxはデータベースに直接アクセスしない。bd showとBeadboxが異なる結果を返す場合、それはBeadboxのバグだ。

パフォーマンス: 10Kイシューデータセットでの実ベンチマーク

beads CLIはベンチマークを公開しており、自分のハードウェアで再現できる。M2 Proで10,000件のイシューを持つDoltデータベースに対してGoベンチマークスイートを実行した実数値:

操作 時間 メモリ データセット
ready作業のフィルター(ブロックされていないイシュー) 30ms 16.8 MB 10Kイシュー
検索(全オープン、フィルターなし) 12.5ms 6.3 MB 10Kイシュー
イシュー作成 2.5ms 8.9 KB 10Kイシュー
イシュー更新(ステータス変更) 18ms 17 KB 10Kイシュー
サイクル検出(5Kリニアチェーン) 70ms 15 KB 5K依存関係
バルククローズ(100件) 1.9s 1.2 MB 順次書き込み
同期マージ(10作成 + 10更新) 29ms 198 KB バッチ操作

これはCLIレベルのベンチマーク: bdがローカルDoltデータベースの読み書きにかかる時間だ。Beadbox UIはその上にレンダリングのオーバーヘッドを追加する。フルスタック(CLIコール + Reactレンダリング + WebSocket伝播)の設計目標:

UI操作 設計目標
エピックツリーレンダリング(100+イシュー) 500ms未満
フィルター適用/クリア 200ms未満
ワークスペース切り替え 1秒未満
リアルタイム更新伝播(エンベデッド) 2秒未満
コールドスタートから利用可能まで 5秒未満

Linearや他のトラッカーとのベンチマーク比較は公開していない。統制された比較を実施しておらず、恣意的な数値は誠実ではないからだ。言えること: データパス全体がローカルということだ。フィルターをクリックして結果が表示されるまでネットワークホップがない。これが重要かどうかは各自のベースラインによる。データセットのサイズと場所に対してLinearが十分速く感じるなら、おそらくそうだ。カンファレンスホテルのWi-Fiで500件のイシューバックログの遅延を体感したことがあるなら、この数値が解決する痛みがわかるはずだ。

再現方法: beadsをクローンし、go test -tags=bench -bench=. -benchmem ./internal/storage/dolt/...を実行して自分のハードウェアと比較する。キャッシュされたデータセットは/tmp/beads-bench-cache/に配置される。

Git統合の深さ: コミットとイシューのリンクを超えて

ほとんどのイシュートラッカーはGit統合を機能チェックボックスとして扱う: コミットメッセージでイシューIDに言及すると、イシューにリンクが表示される。便利だが浅い。

Beadboxはbeadsの上に構築されている。Gitセマンティクスが後付けのインテグレーションではなくストレージレイヤーそのものであるイシュートラッカーだ。基盤のDoltデータベースは、構造化データにGitのマークルツリーデータモデルを実装している。すべてのイシュー変更がコミットになる。すべてのコミットに親がある。コードで使っているのと同じセマンティクスで、イシュー履歴にdolt diffdolt logdolt mergeが使える。

実際に何を意味するか:

イシュー履歴が監査可能。 データベース自体がコミットグラフだ。任意の2時点をdiffして、どのイシューのどのフィールドが変更されたかを正確に確認できる。これは上に後付けした「監査ログ機能」ではない。ストレージフォーマットが監査証跡そのものだ。

ブランチがコードだけでなくイシューにも機能する。 Doltはブランチをネイティブにサポートする。イシューデータベースをブランチして再編成を試み、マージバックするか破棄するかできる。

同期がAPIコールではなくpush/pull。 マルチマシンコラボレーションがgit pushgit pullのように動作する。APIトークンなし、webhookなし、OAuthフローなし。Doltリモートをサーバー(またはDoltHub)に向けてpush。別のマシンがpullする。

コンフリクトについて: Doltは Gitと同じ3-wayマージを使用する。2人が同じイシューの異なるフィールドを編集すればマージが自動解決される。同じフィールドを編集した場合、Dolt CLI(dolt conflicts resolve)で手動解決が必要なコンフリクトになる。Beadboxにはまだコンフリクト解決UIがない。コンフリクトはdoltレベルで処理する。実際には、各人(またはエージェント)が別々のイシューで作業する典型的なパターンでは、コンフリクトはまれだ。しかしチームが同じイシューを頻繁に同時編集するなら、知っておくべき摩擦ポイントだ。Doltマージドキュメントに解決ワークフローの詳細がある。

ネイティブレンダリング: TauriにNode.jsをバンドルする理由

Linearはブラウザタブで動作する。Jira、Asana、他のSaaSトラッカーも同様だ。ブラウザタブはメモリを競合し、OSによってサスペンドされ、レイテンシのフレームを追加するコンポジターを通じてレンダリングする。

BeadboxはTauriで構築されたネイティブデスクトップアプリケーションとして動作する。TauriアプリはChromiumをバンドルする代わりにOSネイティブのWebViewを使うため、通常は小さい(Tauriランタイム自体はシングルデジットMB)。バンドルは一般的なTauriアプリより大きい約160MBで、これは説明に値する意図的なトレードオフだ。

そのうち84MBは組み込みのNode.jsランタイムだ。サイドカーアーキテクチャを採用: TauriがNext.jsサーバーを子プロセスとして生成し、サーバーサイドレンダリング、サーバーアクション、リアルタイム更新のWebSocketレイヤーを処理する。TauriのWebViewはこのローカルサーバーを指す。純粋なRustバックエンドではなくこれを選んだ理由は、Next.jsエコシステムがReact Server Components、サーバーアクション、UIレイヤーの高速なイテレーション速度を提供するからだ。コストはバンドルサイズ。同等のElectronアプリなら400MB以上。純粋なRust + Tauriアプリなら10MB未満だが、構築に3倍の時間がかかり、Reactエコシステムを失う。

ブラウザタブとの実質的な違い: Beadboxは他の47個のブラウザタブとメモリを共有しない専用WebViewプロセスでレンダリングする。100以上のネストされたイシューを持つエピックツリーの展開、フルバックログへのフィルター適用、ワークスペース間の切り替え: これらの操作はレンダラーがリソースを競合しないとき、質的に異なる体験になる。

REST APIではなくCLIで拡張する

LinearにはGraphQL APIがある。よく設計されている。しかしLinearを拡張するということは、彼らのサーバーと通信し、彼らのトークンで認証し、彼らのレートリミットを処理するコードを書くことだ。

Beadboxは別のアプローチを取る: bd CLIがAPIだ。GUIが実行するすべての操作は、ターミナルで使うのと同じコマンドラインツールbdを通る。

今すぐコピペできる3つのワークフロー:

トリアージスイープのためのバルク優先度更新:

# すべてのオープンバグを優先度1(クリティカル)に設定
bd list --status=open --type=bug --json | \
  jq -r '.[].id' | \
  xargs -I{} bd update {} --priority=1

日次ステータスサマリーの生成:

# 過去24時間で何が変わったか?
echo "=== Closed today ==="
bd list --status=closed --json | \
  jq -r '.[] | select(.updated > (now - 86400 | todate)) | "\(.id) \(.title)"'

echo "=== Currently blocked ==="
bd blocked --json | \
  jq -r '.[] | "\(.id) \(.title) (blocked by: \(.blocked_by | join(", ")))"'

echo "=== Ready to work ==="
bd ready --json | jq -r '.[] | "\(.id) [P\(.priority)] \(.title)"'

AIエージェントが作業を作成して担当する:

# エージェントがバグを発見し、登録し、担当する
ISSUE_ID=$(bd create \
  --title "Fix race condition in auth middleware" \
  --type bug \
  --priority 1 \
  --json | jq -r '.id')

bd update "$ISSUE_ID" --status=in_progress --assignee=agent-3

# ... エージェントが作業を実行 ...

bd update "$ISSUE_ID" --status=closed
bd comments add "$ISSUE_ID" --author agent-3 \
  "Fixed in commit abc1234. Root cause: mutex not held during token refresh."

AIコーディングエージェント(Claude Code、Cursor、Copilot Workspace)を実行しているなら、CLIコマンドの実行方法はすでに知っているはずだ。APIクライアントライブラリ不要、認証フロー不要。Unixパイプとシェルスクリプトだけだ。

Beadboxを試すと、エージェントがこれらのワークフローを実行する様子をリアルタイムで可視化できる。

オフラインファーストは機能ではなくアーキテクチャ

一部のクラウドトラッカーは、最近のデータをキャッシュして再接続時に同期する「オフラインモード」を提供している。根本的にオンラインなアーキテクチャに後付けした機能だ。障害モードは予測可能: 古いキャッシュ、同期コンフリクト、静かにキューに入って後で失敗する操作。

Beadboxは最初からオンラインだったことがないため、オフラインで動作する。エンベデッドモードでは、イシューデータベース全体がファイルシステム上のディレクトリだ。サーバープロセスなし。デーモンなし。ネットワークソケットなし。bd CLIがそのディレクトリを読み書きする。Beadboxはfs.watch()で監視し、見つけたものをレンダリングする。

リモートがないから同期するものもない。後で協業を選択する場合、Doltのpush/pullが明示的で可視的な同期を提供する。しかしデフォルトはローカルだ。デフォルトは自分のものだ。

セキュリティについて: エアギャップや機密性の高い環境でBeadboxを評価しているなら、具体的なセキュリティ態勢は以下の通り:

  • 保存時の暗号化: Beadboxは.beads/ディレクトリ自体を暗号化しない。OSレベルのディスク暗号化(macOSのFileVault、LinuxのLUKS、WindowsのBitLocker)に依存する。脅威モデルがデータベースごとの暗号化を要求するなら、これはギャップだ。
  • バックアップ: .beads/ディレクトリは普通のディレクトリだ。cp -rrsync、Time Machine、またはリモートへのdolt pushすべてが動作する。Doltのコミット履歴により、dolt resetで誤った変更をロールバックすることもできる。
  • マシンから出るもの: エンベデッドモードではなし。ネットワークコールはゼロ。デスクトップアプリでは2つのオプショナルなアウトバウンド接続が存在する: Beadboxの更新確認のためのGitHub API(設定で無効化可能)、オプトイン時のPostHogアナリティクス(デフォルト無効、PII収集なし)。いずれもイシューデータを送信しない。

エアギャップ環境、機密プロジェクト、飛行機や電車で作業する開発者にとって、これはあると便利な機能ではない。動作する唯一のアーキテクチャだ。

チームに合ったツールを選ぶ

万能なツールは存在しない。率直な分析を示す:

Linearを選ぶべき場合:

  • 10人以上のチームで中央集権的なプロジェクト管理が必要
  • Slack/GitHub/Figmaインテグレーションに依存
  • 非技術系ステークホルダーがイシュートラッカーにアクセスする必要がある
  • 運用オーバーヘッドゼロのマネージドインフラが欲しい
  • 定期サイクルで出荷するプロダクトチーム

Beadboxを選ぶべき場合:

  • データ主権を重視(イシューがマシンを離れない)
  • 定期的にオフラインまたはネットワーク制限環境で作業
  • プログラムでイシューを読み書きするAIエージェントを管理
  • Gitネイティブのイシュー履歴(branch、diff、merge)が必要
  • 必要なときにビジュアルコンパニオンがあるCLIファーストワークフローを好む
  • エンタープライズ機能が不要なソロ開発者または小規模チーム(1〜10人)

現在のツールを使い続けるべき場合:

  • 切り替えコストが体験している摩擦を上回る
  • チームが現在のトラッカーのAPIに依存するインテグレーションに投資済み
  • ワークフローがすでにツールの意見に合致

Linearからの移行(その他のトラッカー含む)

率直に言う: 現時点でLinearからBeadboxへの自動移行ツールは存在しない。CSVインポートウィザード、APIブリッジ、ステータスマッピングUIはない。

新規で始めるなら問題ない。bd initでイシューを作り始めれば、Beadboxが即座に認識する。摩擦ゼロ。

既存のLinearプロジェクトを移行したい場合、今の実現可能なパスはスクリプトだ: LinearのAPIからエクスポートし(CSVとAPIエクスポートをサポート)、データを変換し、ループ内でbd createを使ってイシューを再作成する。Linear固有のメタデータ(サイクル、プロジェクトビュー、SLAタイマー)は失われるが、タイトル、説明、優先度、ステータスは保持される。移行スクリプトは週末のプロジェクトであり、四半期のインテグレーションではない。

数千件のイシューと何年もの履歴を持つチームにはこれでは不十分だと認識している。適切なインポートパイプラインの構築はロードマップにあるが、まだ出荷していない。移行の摩擦が主要な懸念なら、構築するまで待つか、新規スタートがユースケースに許容できるかを評価してほしい。

はじめよう

Beadboxはベータ期間中無料だ。Homebrewでインストール:

brew tap beadbox/cask && brew install --cask beadbox

すでにbeadsを使っているなら、Beadboxが既存の.beads/ワークスペースを自動検出する。アプリを開けばイシューがそこにある。インポート手順なし。アカウント作成なし。

beadsを初めて使うなら、Beadboxが最初のワークスペースの初期化を案内する。60秒以内にイシューを確認できる。

Beadboxをダウンロード、またはbeadsをチェックして、ローカルファーストのイシュートラッキングが自分のワークフローに合うか確かめてほしい。