コーディングエージェントと組んでいて、僕が最初に困ったのは賢さではありませんでした。忘れることです。セッションが切れると、昨日まで何をしていたかを、エージェントはほぼ覚えていません。Steve Yegge はこれを映画『Memento』や『50 回目のファースト・キス』にたとえました。数分から十数分で文脈がリセットされ、同じ調査をやり直し、6 段の計画の 3 段目でまた別の 5 段計画を立て、道半ばで「完了」と宣言する。markdown の計画書を渡しても、それはエージェントにとって「書き込み専用の記憶」になりがちです。書けるけれど、後から確実には引き出せない。
beads(コマンドは bd)は、この記憶の問題に当てた道具です。Yegge の紹介記事では、beads は「エージェントのための issue 管理ではなく、エージェントのための外部記憶」だと表現されています。本稿では、それが何で、なぜ markdown の TODO と違うのか、中身はどう動いているのか、このリポジトリで実際にどう回しているのか、そして簡易運用で僕が落とし穴を 3 回踏んで本来の同期へ切り替えるまでを、構成のまま記録します。
beads とは何か
beads は、Dolt(版管理つきの SQL データベース)を土台にした、git に紐づく軽量な issue tracker です。issue は手元の Dolt に書き込まれ、git には人間が読める JSONL として書き出されます。データベースの問い合わせ能力と、バージョン管理の追跡可能性を、片方に寄せずに両取りする設計になっています。
要になるのが依存関係の扱いです。issue どうしは型付きリンクで結べます。現行の bd にはリンクの型が 10 種類ありますが、核になるのは 4 つ — blocks(ブロック)・parent-child(親子・epic と子 issue)・related(関連)・discovered-from(作業中に派生して見つかった)。最後の discovered-from はエージェント特有で、「ある作業をしていて気づいた別の作業」を、文章ではなくデータとして残せます。
この依存グラフがあるから、bd ready は「いま着手できる(何にもブロックされていない)作業」だけを返せます。推移的なブロック関係を手元で計算するので、ネットワークも要りません。エージェントは全文を読み直さずに、次の一手を問い合わせるだけでよくなります。
なぜ markdown の TODO ではないのか
散文の計画書でも、やることは書けます。違いは、書いたあとに「引き出せるか」にあります。
| markdown の計画・TODO | beads | |
|---|---|---|
| 形式 | 散文(読んで解釈する) | 構造化データ(クエリする) |
| 依存関係 | 文章に埋め込む | 型付きリンク(blocks / parent-child / discovered-from) |
| 次の作業 | 全文を読み直して判断 | bd ready が未ブロックの作業だけ返す |
| 履歴 | 上書きで消えやすい | git / Dolt に版管理で残る |
| 複数エージェント | 衝突しやすい | hash ID で衝突回避・セル単位でマージ |
散文では、依存関係が文章に溶けてしまいます。次に何をするかは、毎回その文章を読み直して解釈するしかない。やがて古い計画書と新しい計画書が混ざり、エージェントは「ディスクにあるもの」しか知らないまま、矛盾した指示の中で迷います。構造化されていれば、依存はクエリできるデータになり、「次の作業」は計算で出せる。差は便利さではなく、引き出せるかどうかにあります。
中身はどう動いているのか — Dolt・hash ID・二つの履歴
道具を信用するには、中で何が起きているかを一段だけ知っておくのが近道です。beads の仕組みは、大きく 4 つに分けて眺められます。
土台の Dolt。 Dolt は「データ版の git」とよく説明される、コミット・ブランチ・diff・マージを備えた SQL データベースです。git がファイルの行を追跡するように、Dolt はテーブルのセルを追跡します。issue の 1 件は Dolt のテーブルの 1 行で、bd close はその行の更新であり、更新はコミットとして履歴に残る。だから bd history <id> で「この issue はいつ、誰が、どう変えたか」を遡れます。beads はこの Dolt を埋め込みで抱えるので、サーバを立てる必要はありません。.beads/embeddeddolt/ がデータベースの実体で、bd コマンドが必要なときだけ静かに開きます。
hash の ID。 issue の ID が cs-nxy6 のような hash なのは、趣味ではなく並行対策です。連番だと、別々のブランチで同時に issue を切った瞬間に番号が衝突します。ランダムな hash なら、事前の調整なしで衝突をほぼ避けられる。子 issue は cs-nxy6.1 のように親の ID にぶら下がり、epic と子の階層が ID だけで読み取れます。
二つの履歴。 このリポジトリの git origin には、いま履歴が二本並んでいます。一本はコードの refs/heads/main。もう一本は issue データの refs/dolt/data です。後者はブランチ一覧にも git log にも現れませんが、git ls-remote origin 'refs/dolt/*' を叩くと見えます。bd dolt push / bd dolt pull が同期するのは、この隠れた参照とローカルの Dolt です。コードと issue が同じ remote に住みながら、互いの履歴を汚さない。冒頭から出てきた issues.jsonl は、この本流とは別に、人間と viewer のために書き込みのたび(間引きあり)に再生成される書き出しです。
記憶の階層。 「外部記憶」とひとくちに言っても、実際には層が分かれています。
| 層 | 入口になるコマンド | 何を覚えるか |
|---|---|---|
| 作業 | bd create / bd ready / bd close | 何をするか・いまの状態・依存関係 |
| 経緯 | bd comment / bd note | なぜそう判断したか |
| 知識 | bd remember | リポジトリ全体で効く事実(正準ファイルの場所など) |
| 想起 | bd prime | セッション開始時に、上の 3 層を束ねて文脈へ注入する |
エージェントが忘れても、どこかの層に残っていれば引き出せます。逆に言えば、どの層にも書かれなかったことは、次のセッションには存在しません。あとで出てくる「規律」の話は、要するに「どの層に何を書くかを人間が決めておく」という話です。
このリポジトリでの実践
このサイトのリポジトリは、タスク管理を全面的に beads に寄せています(issue の接頭辞は cs)。流れはいつも同じです。bd ready で着手できる issue を見つけ、bd update --claim で確保し、作業ブランチを切る。実装して PR を出し、Cloudflare の preview で目視し、問題なければ squash merge して bd close する。
- 01bd ready
- 02claim
- 03ブランチ
- 04PR・preview
- 05close
規律としていくつか決めています。その場限りの markdown TODO は使わず、タスクは必ず beads に置く。セッションを越えて効く知識 — たとえば「声・匿名化のガードレールの正準がどのファイルにあるか」といった、コードを読んでも分かりにくい事実 — は bd remember に残す。新しいセッションは bd prime で文脈を復元してから動き出す。この記事自体も、書く前に cs-pkn という bead として起票してから着手しています。サイトが「AI 駆動で自社のオペを回す」と言うなら、その発信の一歩目もまた tracker に載っているのが筋だ、というだけのことです。
この文章を書いている時点で、このリポジトリの beads は 203 件の issue を抱えていて、うち 126 件が閉じています。bd ready が「いま着手できる」と返すのは 63 件。この数字を僕が暗記している必要はありません。覚えているのは tracker の側で、僕は問い合わせるだけです。
記憶が git に触れる場所 — 簡易運用で 3 回踏んで、本来の同期へ
ここは、当事者にしか書けない話です。beads は本来、Dolt の同期機構(refs/dolt)でクローン間の状態を突き合わせる設計で、git に出る JSONL は受動的な書き出しに過ぎません。公式の同期ドキュメントは、JSONL の取り込みを同期の代わりに使う運用を anti-pattern だと明言しています。それを知ったうえで、ジャムチはソロで小規模だからと、Dolt remote を張らず、git に commit する .beads/issues.jsonl を正本にする簡易運用から始めました。同期の機械を一段まるごと省いた、素朴なほうの構えです。
その素朴さには代償がありました。beads は git の post-checkout / post-merge フックで、「チェックアウト中のブランチの JSONL」を Dolt に取り込みます。つまり、あるブランチで bd close したあとに別のブランチへ切り替えたり git pull すると、取り込まれる JSONL の中でその issue はまだ open のままなので、close が巻き戻ります。
これは想像で書いているのではありません。6 月 29 日、7 月 1 日、7 月 3 日。1 週間のうちに 3 回、閉じたはずの issue が open に戻りました。1 回目は偶然だと思いました。2 回目で原因を特定し、順序の儀式でしのぐことにしました — 先に同期する、それから close、bd export、commit、push。close のあとに pull しない。しのげてはいたのですが、この規律はセッションごとにエージェントへ思い出させる必要のある類のもので、運用メモが 1 枚増え、それでも 3 回目が起きました。
3 回目のあとで、前提を数え直しました。「ソロで小規模だから同期は要らない」が根拠だったはずが、実際のリポジトリは agent 用の worktree が 14 本、全部で 30 本あまりという、むしろ並行度の高い状態で回っています。そして本来の同期は、別のサーバを立てなくても、同じ git origin の refs/dolt/data に張れる。省いて得ていた簡素さは思っていたより小さく、払っている税 — 順序の儀式、再発、増える運用メモ — のほうが大きい。釣り合いが崩れたと判断して、bd dolt remote add origin で本来の同期へ切り替えました。
正直に書くと、切り替えは 1 コマンドでは終わりませんでした。remote を張っただけでは巻き戻りが再現したのです。調べると、「sync.remote が設定されていれば JSONL の取り込みをスキップする」という修正は手元のバージョンの beads にまだ入っておらず、beads 本体の更新とデータベースのスキーマ移行まで済ませ、close → ブランチ切替で巻き戻らないことを再現テストで確かめて、ようやくこの落とし穴は消えました。記憶をインフラに預けると決めたなら、そのインフラが git のどの操作でどう動くかまでを、こちらが引き受ける必要があります。
並行実行にも似た芯があります。Dolt の実体は main の作業ツリーに住んでいるので、複数のセッションが worktree を分けて動いても、データベースは 1 つです。だから並行作業の最中に bd dolt push はせず、作業は隔離した worktree で進めて、相手の未完了の状態を巻き込まないようにしています。hash ID が採番の衝突を避けてくれても、共有された DB という制約は残ります。
要するに、beads は記憶をくれますが、正本をどこに置き、git がそれにどう触れるかは、自分で決める設計です。ジャムチは簡素なほうから始めて、3 回踏んで、定石に戻りました。最初の選択を後悔はしていません。ただ、定石から外れるなら、その税を数えておくこと。釣り合いが崩れたら、意地を張らずに戻ること。今回持ち帰ったのは、この 2 行です。
記憶はインフラに、規律は人に
beads を入れただけでは効きません。実践者の Ian Bull は、使ってみた記録の締めで、率直にこう書いています。
The tool provides the memory. You provide the discipline.
道具が記憶を持ち、規律は人が用意する——訳は僕によるものです。この一文が、beads を入れる勘所を言い当てていると思います。
エージェントは放っておくと、文脈の圧力で指示を忘れます。だから人間の側に、いくつかの小さな型が要る。Yegge のベストプラクティスから、効いているものを挙げます。
- 約 2 分を超える作業は、思いついた時点で issue にする。
- working set は小さく保つ。issue が増えて
issues.jsonlがおよそ 25k トークン(ファイル全体を読み込める上限)を超えると、エージェントがそれを読めなくなる。Yegge の目安は「200 を超えたら片付けを考え、500 は超えない」。原文が挙げるbd cleanupというコマンドは現行の CLI にはもう無く、いまは古い closed を削るbd pruneと、履歴を畳むbd gcがこの片付けを担います。 - エージェントは 1 タスクごとに区切って終える。続きは beads が覚えている。
- セッションの終わりに状態を更新し、push してから降りる。次の自分(や別のエージェント)が
bd readyから再開できる。
白状すると、このリポジトリは執筆時点で 203 件。まさにその目安を跨いだところです。なのでこの節を書きながら、片付けの issue(cs-8np6)を 1 件積みました。「2 分を超える作業は issue にする」の、ささやかな実演でもあります。
要点は、記憶をインフラ側に移し、判断と規律だけを人の手に残すことにあります。少人数でも、昨日のノードから今日のノードへ作業を確実に手渡せれば、開発は途切れません。中継網が荷物を次の駅へ運ぶように、tracker が文脈を次のセッションへ運ぶ。レバレッジは規模ではなく、受け渡しの設計から出てくる、と僕は考えています。
参考: beads(GitHub・gastownhall/beads)、Introducing Beads: A coding agent memory system(Steve Yegge)、Beads Best Practices(Steve Yegge)、Beads - Memory for your Agent(Ian Bull)。このリポジトリでの beads 運用ルールは CLAUDE.md に置いています。

