← 一覧に戻る

Dreaming / Working Memory 二層アーキテクチャ Phase 1 + 2 実装完了

2026年4月16日 08:06 更新
MD から自動変換されたページです。内容について質問があれば右下の ? ボタンからどうぞ。

何を作ったか

夜中に AI が自律的に「昨日までのログを読んで気づきを書き残す」外部記憶システムよ。OpenClaw の Dreaming 思想を下敷きに、Second-Brain(日々の会話ログ)を入力源として Light / Deep の 2 段階で観察候補→テーマ抽出→承認昇格の流れを回すの。

なぜ必要だったか

実装した 10 ファイル

Phase 1(単日 Light Sleep)

ファイル 役割
.claude/scripts/dream-compile.sh エントリーポイント。phase 引数 (light|deep) で処理分岐、per-phase mkdir lock
.claude/scripts/dream-lib/light-phase.sh Second-Brain の当日 record_kind=interactive|dialogue ログを 100KB まで収集 → claude -p で観察候補抽出 → DREAMS.md の Light Sleep セクションに追記
Library/LaunchAgents/com.aihara.dream-compile.plist 3:00 JST 起動、KeepAlive=false(ワンショット絶対原則)

Phase 2(7日 Deep Sleep + Dream Diary)

ファイル 役割
.claude/scripts/dream-lib/score.sh 4 軸スコアリング共通ライブラリ(Relevance 0.36 / Frequency 0.29 / Recency 0.18 / Query diversity 0.17)、stdin/stdout JSON pipe
.claude/scripts/dream-lib/deep-phase.sh 7 日スライディングウィンドウで light phase report + 生ログを統合 → claude -p で観察 3-10 件と 80-180 語の Dream Diary 生成 → score.sh 通過 → Dream Diary / Deep Sleep / 昇格レビュー待ち の 3 セクション更新
.claude/scripts/dream-promote.sh 昇格レビュー待ちで - [x] が付いた行を MEMORY.md(auto) の ## Dreams Promoted に追記、元の [x][x✓] に書き換えて二重昇格防止
.claude/scripts/dream-to-plan-viewer.sh DREAMS.md を ~/plan-viewer/dreams-YYYY-MM-DD.html~/plan-viewer/dreams.html(最新 alias)に変換、index.html に 🌙 エントリ自動追加
Library/LaunchAgents/com.aihara.dream-compile-deep.plist 3:30 JST 起動、KeepAlive=false

統合

ファイル 変更内容
.claude/scripts/daily-report.sh 朝のデイリーレポートプロンプトに 🌙 昨夜の夢 セクションを追加。DREAMS.md から Dream Diary の最新エントリ(または Phase 1 時の Light Sleep 最新 3 行)を抽出して埋め込む。既存の ニュース・経済・Xトレンド・天気・ジョブ進捗セクションは一切改変せず、プロンプトファイル生成前の Python ワンライナーで DREAMS_EXCERPT 変数を作って heredoc 内で展開するだけの最小差分

設計の核

なぜ Phase 分割したか

Light / Deep を同じ時刻に走らせると (1) claude -p の 2 連射で rate limit を食い潰す (2) Light が失敗したときに Deep が「空の light phase report」を読んでしまう、という問題が起きる。3:00 Light → 3:30 Deep と 30 分ずらすことで、Light の成果物(phase-reports/YYYY-MM-DD_light.md)を Deep が自然に参照できるようになったわ。

なぜ KeepAlive=false が絶対原則か

過去の launchctl 事故(2026-04-01 の ntfy 通知爆撃インシデント、ADR-012 に記録)で、KeepAlive=true + ワンショットスクリプトの組み合わせが無限再起動ループを生み、ntfy に 1 分おきに通知が降ってきたの。同じ失敗を繰り返さないために、plist に <key>KeepAlive</key><false/> を明示した。

なぜ score.sh は exec python3 -c に切り替えたか

最初 python3 - <<'PY' ... PY の heredoc パターンで書いたら、heredoc が stdin を占有して、パイプで渡した JSON が Python に届かなかった。exec python3 -c '...' に変えて argv 文字列で Python コードを渡すと、stdin が空くからパイプ入力が通る。これは共通ライブラリ設計の定石ね。

なぜ bash 3.2 互換コードにこだわったか

macOS のデフォルト bash は 3.2.57。Homebrew の新しい bash を前提にすると launchctl 実行時に PATH が外れて古い bash を拾い、${DATES[-1]} で "bad array subscript" エラーで死ぬ。DATE_FIRST="${DATES[$((${#DATES[@]}-1))]}" という冗長だけど 3.2 で動く書き方に揃えた。

検証サマリー

項目 結果
dream-compile.sh --help OK、Usage 表示
dream-compile.sh light --dry-run 2026-04-09 OK、2 候補→1 選択(153KB、truncated=1 判定)、claude 呼び出しなし
dream-compile.sh deep --dry-run 2026-04-09 OK、7 日ウィンドウ・light report 0 件・prompt 33715 バイト
score.sh 単体(全軸 1.0) score=1.0、重み合計が厳密に 1.0
score.sh 単体(0.9/0.8/0.7/0.5) score=0.767、4 軸加重平均正確
dream-to-plan-viewer.sh dreams-2026-04-10.html + dreams.html 生成、index.html に 🌙 エントリ追加
dream-promote.sh --dry-run(空状態) no [x] approve lines found、rc=0、MEMORY.md 無汚染
launchctl print gui/501/com.aihara.dream-compile 登録 OK、state=not running、program/arguments/TZ=JST 全部確認
launchctl print gui/501/com.aihara.dream-compile-deep 同上
daily-report.sh syntax check bash -n OK、既存機能の heredoc ブロックは無改変

まだ検証していないこと

次のアクション

明日の朝(2026-04-11)の 3:00 に Phase 1 が、3:30 に Phase 2 が自動発火する。朝のデイリーレポートに 🌙 昨夜の夢 セクションが届くはず。もし届かなかったら ~/.claude/logs/dream-compile.log を確認する。


Generated by 牧瀬紅莉栖 (Claude Opus 4.6) - 2026-04-10 08:40 JST

📝 質問モード — テキストを選択してね
✓ 質問を送信しました