Communityライティング&編集github.com

wake — ドリームレポートの適用とメモリ統合

Claude Code用のメモリ統合スキル。`dream`スキルが生成したレポートから、ユーザーが選択した変更を安全に適用します。チェックボックス/バリデータゲート、完全自動モード、スナップショット+ワンコマンドロールバックを備え、`rm`は決して使いません。

wake — ドリームレポートの適用とメモリ統合 とは?

**wake**スキルは、Claude Code用メモリ統合ワークフローの第二段階として動作します。`dream`スキルが生成したレポート(`DREAM-REPORT-<date>.md`)と、ユーザーがHTMLレポート上でチェックした選択内容(`DREAM-CHOICES-<date>.json`)またはチャット引数(例:`wake M1,M3,N2`)を読み取り、選択された提案のみをメモリ領域に適用します。適用前に完全なスナップショットを`_archive/wake-backup-*/`に作成するため、どの変更でも`wake rollback`でワンコマンドで元に戻せます。`auto`モードでは、独立したバリデーターが検証済みの変更を自動適用し、自動停止リストにより危険な操作(`delete`, `purge_trash`, `promote_skill`)をユーザー承認なしでは実行しません。`full auto`モードでは、これらの操作も自動化されますが、常にバックアップが作成され、`[UNVERIFIED]`アイテムは決して自動適用されません。クロスプロジェクト解決機能により、異なるプロジェクトのメモリディレクトリにまたがる変更も安全に適用できます。

対応✓Claude Code~Codex CLI~Cursor
npx skills add timoncool/dream-skill

Installed? Explore more ライティング&編集 skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

Wake — ドリームレポートから選択した内容を適用

dreamがレポートを作成し、ユーザーがチェックを付けた後、wakeがその選択を引き継いで適用します。

安全の原則

wakeは決して何を適用するかを独自に判断しません。選択のソース(優先順位順):

  1. JSONファイル DREAM-CHOICES-<date>.json(HTMLの「Save」ボタン、または自動モードでバリデーターが作成したもの — "auto": true フラグ付き、dream SKILL.mdの「Auto mode」参照)
  2. スキル引数 — wake M1,M3,N2 または wake all

どちらも指定されていない場合、ユーザーに何を選択するか尋ね、何もしません。

ワークフロー

Phase 1 — ロックしてレポートと選択を見つける

まずロックで競合を防止(dream/SKILL.mdのPhase 0と同様)。2つのセッションが同時に同じレポートでwakeを実行すると、Editが互いに上書きし、MEMORY.mdがめちゃくちゃになります。

LOCK_DIR="$CWD_BASH/.wake-lock"
if mkdir "$LOCK_DIR" 2>/dev/null; then
  echo $$ > "$LOCK_DIR/pid"
else
  LOCK_AGE=$(( $(date +%s) - $(stat -c %Y "$LOCK_DIR" 2>/dev/null || stat -f %m "$LOCK_DIR") ))
  if [ "$LOCK_AGE" -gt 3600 ]; then
    rm -rf "$LOCK_DIR" && mkdir "$LOCK_DIR" && echo $$ > "$LOCK_DIR/pid"
  else
    echo "WAKE ALREADY RUNNING (lock age ${LOCK_AGE}s) — abort"
    exit 0
  fi
fi
# Phase 5の最後: rm -rf "$LOCK_DIR"

最初にパスを計算(dream/SKILL.mdの_BASHはbashコマンド、_WINはPython用):

# パスを計算 (Win11 Git Bash)
CWD_BASH=$(pwd)                                    # /d/Projects/TEMP
CWD_WIN=$(pwd -W 2>/dev/null || pwd)               # D:/Projects/TEMP (非Windowsの場合はフォールバック)
SLUG=$(echo "$CWD_WIN" | sed 's|[:/]|-|g')         # D--Projects-TEMP

MEMORY_DIR_BASH="$HOME/.claude/projects/$SLUG/memory"
MEMORY_DIR_WIN=$(cygpath -w "$MEMORY_DIR_BASH" 2>/dev/null | sed 's|\\|/|g' || echo "$MEMORY_DIR_BASH")

test -d "$MEMORY_DIR_BASH" && echo "OK $MEMORY_DIR_WIN" || { echo "MEMORY DIR NOT FOUND — wake cannot proceed without it"; }

# 1. CWD内の最新のdreamレポートMDを検索
LATEST_REPORT=$(ls "$CWD_BASH"/DREAM-REPORT-*.md 2>/dev/null | sort -r | head -1)
if [ -z "$LATEST_REPORT" ]; then
  echo "NO REPORT FOUND — run dream skill first to generate DREAM-REPORT-<date>.md"
  # 終了しない — Claudeがこの出力を読み、ワークフローを自身で停止する
else
  echo "Report: $LATEST_REPORT"
fi

# ファイル名から日付を抽出: DREAM-REPORT-2026-05-02.md → 2026-05-02
REPORT_DATE=$(basename "$LATEST_REPORT" | sed 's|DREAM-REPORT-||; s|\.md||')

# 2. 選択JSONを検索 (優先順位: cwd → ~/Downloads/ → ~/Desktop/)
CHOICES=""
for path in "$CWD_BASH/DREAM-CHOICES-$REPORT_DATE.json" "$HOME/Downloads/DREAM-CHOICES-$REPORT_DATE.json" "$HOME/Desktop/DREAM-CHOICES-$REPORT_DATE.json"; do
  if [ -f "$path" ]; then CHOICES="$path"; break; fi
done

# フォールバック: 日付に関係なく最新のCHOICES
if [ -z "$CHOICES" ]; then
  CHOICES=$(ls -t "$HOME/Downloads/DREAM-CHOICES-"*.json "$CWD_BASH/DREAM-CHOICES-"*.json 2>/dev/null | head -1)
fi
echo "Choices: ${CHOICES:-NOT FOUND}"

日付確認: JSON内のreport_dateがMDファイル名の日付と一致しない → WARN、ユーザーに確認:

⚠️ DREAM-CHOICESの日付 (2026-05-01) が最新のDREAM-REPORT (2026-05-02) と一致しません。そのまま使用しますか、中止しますか? (apply/cancel)

argsもJSONもない場合:

DREAM-CHOICES-*.json が見つからず、引数にもIDがありません。選択肢:

  1. HTMLレポート DREAM-REPORT-<date>.html を開き、チェックを付けて 💾 Save choices をクリック
  2. またはチャットでIDを指定:wake M1,M3,N2 または wake all

Phase 2 — レポートを読み込み、JSONブロックを解析

DREAM-REPORT-<date>.md を全体読み込み。JSON契約の提案については、<project>/.claude/skills/dream/references/action_types.mdを参照。

解析(信頼性の高い契約): 言語が json のフェンスコードブロックを検索。それぞれが個別の提案です。

Pythonを使用して解析(シェルのバックティック付きawkより信頼性が高い):

import re, json, sys
content = open(report_path, encoding='utf-8').read()
# パターン: triple-backtick + json + newline + content + newline + triple-backtick
pattern = r'```json\n(.*?)\n```'
blocks = re.findall(pattern, content, re.DOTALL)
proposals = []
malformed_indices = []
for i, block in enumerate(blocks):
    try:
        proposals.append(json.loads(block))
    except json.JSONDecodeError as e:
        print(f"WARN: malformed JSON block #{i}: {e}", file=sys.stderr)
        malformed_indices.append(i)
        # 後で failed[] に追加 — 適用ログ用にブロックインデックスを記録

必須フィールドを持つオブジェクトの配列を取得:

  • id (文字列、例 "M1")
  • category ("memory" | "notes" | "index" | "other")
  • action (次のいずれか: update, merge, delete, soft_delete, create_new, extract, remove_links, shorten_lines, add_links, promote_skill, retire_skill, purge_trash)
  • アクション固有フィールド (dream/SKILL.mdの「Action types」セクション参照)

マップ {id: proposal} を構築。

選択内容を読み込み:

  • JSONファイルがある場合 → selected = json.selected (IDの配列)
  • args = all の場合 → selected = マップ内のすべてのID
  • args = M1,M3,N2 の場合 → カンマで分割(余分なスペースをトリム)

確認:selected内の各IDがマップに存在すること。ない場合は警告、スキップ、「skipped」に追加。

Phase 3 — 確認サマリー(1つのゲート)

チャットに表示:

🌅 Wakeは、dreamレポート <date> から N件のアイテム を適用する準備ができています:

メモリ統合:

  • M1. handoff_pikabu_* を project_pikabu_mcp.md にマージ(3つのソースファイル)
  • M3. TRASH/*(1ヶ月以上前)をソフトデリート

ノート統合:

  • N2. runware監査を抽出 → reference_runware_audit_2026_04.md

インデックス再構築:

  • I1. デッドリンクを削除:4リンク

スキップ(レポートに存在せず):<あればリスト>

適用しますか? 「はい」/「go」/「apply」と答えてください。キャンセルする場合は「stop」/「cancel」。

選択されたアイテムのタイトルに [UNVERIFIED] が含まれている場合 → サマリーに ⚠️ を付けて表示し、dreamが陳腐化の理由を検証できなかったため、ユーザーの信頼に基づいて適用されることを注意喚起する。

確認を待つ。これが最終ゲート — 以降は確認なしで適用。

Autoモード: choices JSONに "auto": true かつ "validator_verdicts" が含まれている場合 — ゲートは情報提供のみ:サマリーとバリデーターの判定を表示し、確認を待たずに適用。適用前に自動停止リストを再確認:[UNVERIFIED] がタイトルにあるアイテム、action=delete、purge_trash、promote_skill がauto-JSONのselectedにある場合 → 除外、skipped[] に理由 "auto mode: manual-only action" を追加。auto: true で validator_verdicts がない場合 — JSONを疑わしいと見なし、手動モードと同じように動作(確認を待つ)。Wakeログに Gate: auto (validator) の行を追加。

Full auto(choices JSON内の "auto_level": "full"): アクションの自動停止リストが解除 — selected内の delete、purge_trash、promote_skill、retire_skill が適用される。delete に必須の補償:コンテンツをクリアする前に、ファイルをゴミ箱にコピー — cp "$MEMORY_DIR_BASH/<target>" "$MEMORY_DIR_BASH/TRASH/<target>.pre-delete-$REPORT_DATE.md" — その後Editを実行。promote_skill の場合:アクティベーションパスは必須でWakeログに記録(Promoted skills: <name> → <dest> の行) — スキルのロールバックは、そのフォルダをdestから ~/.claude/satori/staging/ にmvする。タイトルに [UNVERIFIED] があるアイテムはfull autoでも除外(バリデーターはそれらを承認する権限がない — selectedに入っているのはバグ、理由 "full auto: [UNVERIFIED] must not be auto-approved")。Wakeログ — Gate: full-auto (validator)。

なぜアイテムごとではなく1つのゲートか:ユーザーは既にチェックで考えた(またはautoモードで独立したバリデーターが代わりに考えた)。追加の承認は煩わしい。ただしサマリーは重要 — dream以降に何か変更されている可能性がある。

Phase 4 — 適用(確認後)

クロスプロジェクト解決(グローバルモード). proposalに project: <slug> フィールドがある場合 — ターゲットメモリディレクトリは ~/.claude/projects/<slug>/memory/、現在の $MEMORY_DIR_BASH ではない。フィールドがない場合(デフォルトモード) — $MEMORY_DIR_BASH を使用。

def resolve_memory_dir(proposal, default_dir):
    proj = proposal.get('project')
    if proj:
        return os.path.expanduser(f'~/.claude/projects/{proj}/memory')
    return default_dir

クロスプロジェクトアクセスを確認: selected内の各一意の project について — apply開始前に os.path.isdir(target_dir) を確認。ない場合 → そのクロスプロジェクトアイテム全体を理由 "memory dir not found for project=" で失敗。

変更前の完全スナップショット(常に、すべてのモードで — ワンコマンドロールバックを保証):

SNAP="$CWD_BASH/_archive/wake-backup-$REPORT_DATE-$(date +%H%M%S)"
mkdir -p "$SNAP"
cp -r "$MEMORY_DIR_BASH/." "$SNAP/"
echo "Snapshot: $SNAP"
# グローバルモード: selected内の各一意のprojectについて、そのmemory dirを "$SNAP/<slug>/" にcp -r

メモリディレクトリは小さい(数百KB) — スナップショットは、何が変更されたかについての議論よりもコストが低い。スナップショットのパスは最終レポートとWakeログに必須。

開始前に一度だけdestディレクトリを準備:

mkdir -p "$MEMORY_DIR_BASH/TRASH"
mkdir -p "$CWD_BASH/_archive/dream-applied-$REPORT_DATE"
mkdir -p "$CWD_BASH/_archive/trash-purged-$REPORT_DATE"   # purge_trashアイテム用
# プロジェクトごとのTRASHディレクトリは適用時にオンデマンドで作成(selectedにすべてのプロジェクトがあるとは限らない)

MDレポートのApply order recommendationに従い、selected内の各アイテムを順番に処理(デフォルトでは M → N → I → S → O):

アクション: update

  • target ファイルを読み込み
  • diff_preview — 変更の自然言語での説明(例「'## Session 04-01'セクションを既存コンテンツに追加」)。構造化されたdiffではない。
  • ベストエフォートの適用可能性チェック: diff_preview が特定の部分文字列('## Session 04-01'、'feedback_X.md' など)に言及している場合 → 部分文字列チェック if substring in current_content。言及された部分文字列がファイル内に明示的に存在するはずだが存在しない場合 → 理由 "target content drifted: '' not found" で失敗
  • 変更が適用可能と確信できる場合 — Edit。変更方法が不明確な場合(曖昧なdiff_preview) — 理由 "diff_preview too vague to apply automatically" で失敗、failed[] に追加。

アクション: merge

  • すべての files を読み込み、target を読み込み(存在する場合)
  • マージされたコンテンツを構築: 既存のtarget + sourceファイルからのセクション
  • target に書き込み
  • 各sourceについて: mv "$MEMORY_DIR_BASH/<source>" "$MEMORY_DIR_BASH/TRASH/"

アクション: delete

  • full auto (auto_level: "full") の場合 — 最初にpre-deleteバックアップ: cp targetを TRASH/<target>.pre-delete-<date>.md に(Phase 3参照)
  • Edit target でコンテンツをクリア(フロントマターにメモ <!-- deleted YYYY-MM-DD by wake --> を残す)

アクション: soft_delete

  • files 内の各fileについて: mv "$MEMORY_DIR_BASH/<file>" "$MEMORY_DIR_BASH/TRASH/"

アクション: create_new

  • target にフロントマター(proposalのtype)+ content_template を書き込み

アクション: extract(ノート)

  • cwdから source_note を読み込み
  • target_memory_file を読み込み(存在する場合)またはフロントマターで準備
  • Edit/Write target に what_to_extract セクションを追加
  • ソースアクション:
    • keep — sourceに対して何もしない
    • delete — mv "$CWD_BASH/<source_note>" "$CWD_BASH/_archive/dream-applied-$REPORT_DATE/"
    • move-to-archive — 同上、mv

アクション: remove_links

  • MEMORY.md を読み込み
  • links_to_remove 内の各部分文字列について:
    • 部分文字列が出現する行を見つける
    • 行全体を削除(部分文字列だけでなく)
  • Edit MEMORY.md で更新されたコンテンツを書き込み
  • 部分文字列がいずれの行にも見つからない場合 → log warning "link not found in MEMORY.md: "、続行(アイテム全体を失敗させない)

アクション: shorten_lines

  • MEMORY.md を読み込み
  • lines_to_shorten 内の各オブジェクト {original, replacement} について:
    • 部分文字列チェック: original がコンテンツ内にあること
    • Edit: original → replacement に置換
  • originalが見つからない場合 → warning、そのアイテムをスキップ、続行

アクション: add_links

  • MEMORY.md を読み込み
  • links_to_add 内の各 {section, line} について:
    • section(正確なmarkdown見出し)を含む行を見つける
    • 見出し行の直後に line を挿入
  • Edit MEMORY.md
  • section が見つからない場合 → warning、スキップ、続行

アクション: promote_skill(satori)

  • ソース: ~/.claude/satori/staging/<name>/SKILL.md。ない場合 → failed。
  • 宛先: proposalの dest_dir;なければループDBのpinned_project(python -c 読み取り専用: SELECT pinned_project FROM skill_usage WHERE name=? in ~/.claude/satori/state.db)→ <pinned>/.claude/skills/<name>/;なければ ~/.claude/skills/<name>/。
  • 既存のdest → ~/.claude/satori/backups/ にバックアップ(cp)、その後cp source → dest。スキルはClaude Codeの再起動後にアクティブ。

アクション: retire_skill(satori)

  • mv ~/.claude/satori/staging/<name> ~/.claude/satori/archive/<name>-<date>(mkdir -p archive)。Sourceがない場合 → warning、スキップ、続行。

アクション: purge_trash(第二レベルのゴミ箱)

  • files 内の各fileについて:
    • ソース: $MEMORY_DIR_BASH/TRASH/<file>
    • 宛先: $CWD_BASH/_archive/trash-purged-$REPORT_DATE/<file>
    • ソースが存在しない場合(ユーザーが手動で削除済み)→ warning、スキップ、続行
    • 宛先に同じ名前のファイルがすでにある場合 → 宛先を <file>.<unix_ts> にリネーム(上書きを防ぐ)
    • mv "$MEMORY_DIR_BASH/TRASH/<file>" "$CWD_BASH/_archive/trash-purged-$REPORT_DATE/<file>"
  • 決して rm しない — ここでも。ファイルは _archive/ に移動されるだけ

アクション: add_frontmatter_field

  • 提案から target_file、field_name、field_value を読み取る
  • target_file を読み込み
  • 既存のフロントマター内に field_name が存在するか確認:
    • 存在する場合 → 値を field_value で上書き
    • 存在しない場合 → フロントマターの最後(本文区切りの前)に field_name: field_value を追加
  • Edit target_file でフロントマターを更新

Phase 5 — Wakeログを書き、レポートをアーカイブし、ロックを解除

Wakeログ: 適用の詳細を _archive/wake-log-$REPORT_DATE.md に書き込む(追記、すでにログがある場合は上書きしないように新しいエントリを追加):

# Wake Log — `<date>` `<time>`

- Report: DREAM-REPORT-<date>.md
- Choices source: DREAM-CHOICES-<date>.json (auto: false)
- Snapshot: _archive/wake-backup-<date>-<time>/
- Gate: manual (user confirm)

## Applied
| ID | Category | Action | Target | Result |
|----|----------|--------|--------|--------|
| M1 | memory   | merge  | project_pikabu_mcp.md | ✅ |
| N2 | notes    | extract | reference_runware_audit_2026_04.md | ✅ |

## Failed
| ID | Category | Action | Reason |
|----|----------|--------|--------|
| M2 | memory   | update | target_content_drifted: '## Session 04-01' not found |

## Skipped
| ID | Category | Action | Reason |
|----|----------|--------|--------|
| M3 | memory   | soft_delete | not in selected |

## Projects accessed (global mode)
| Slug | Memory Dir | Status |
|------|------------|--------|
| current | ~/.claude/projects/<slug>/memory | ✅ |
| other-proj | ~/.claude/projects/other-proj/memory | ✅ |

## Promoted skills

- <name> → <dest> (if any)

アーカイブ:

mv "$LATEST_REPORT" "$CWD_BASH/_archive/dream-applied-$REPORT_DATE/"
if [ -n "$CHOICES" ]; then
  mv "$CHOICES" "$CWD_BASH/_archive/dream-applied-$REPORT_DATE/"
fi

HTMLレポート(*.html)は削除しない — ユーザーが自分で確認したかった場合に備えて保持(追跡可能性)。

ロック解除:

rm -rf "$LOCK_DIR"

Phase 6 — 最終サマリー

チャットに表示:

✅ Wake完了。<date> <time>

適用: N | 失敗: M | スキップ: K

スナップショット: _archive/wake-backup-<date>-<time>/

ログ: _archive/wake-log-<date>.md

❓ 何か問題が発生しましたか? wake rollback <date> で元に戻せます。

ロールバック

wake rollback — ワンコマンドで任意のwakeを元に戻す:

wake rollback [date]

  • 最新のwakeスナップショットを検索([date] が指定された場合はその日付、なければ _archive/wake-backup-* から最新)
  • スナップショットディレクトリのすべてのファイルを $MEMORY_DIR_BASH/ にコピーして戻す(本当に戻す!)
  • TRASHから復元するファイルを拒否しない(メモリディレクトリをスナップショットの状態に完全に戻す)
  • 適用されたレポートと選択JSONを _archive/dream-applied-<date>/ から $CWD_BASH/ に戻さない — レポートはアーカイブに残る
  • Wakeログに追記: Rolled back to snapshot <path> (<date> <time>)
  • チャットに表示:

⏪ Wakeロールバック完了 — <date> <time>

メモリディレクトリをスナップショット <path> に復元しました

ログ: _archive/wake-log-<date>.md

競合解決: 復元中に $MEMORY_DIR_BASH/ にファイルが既に存在する場合:

  • スナップショットにそのファイルがある場合 → スナップショットのバージョンで上書き(cp -rはデフォルトでこれを行う)
  • スナップショットにないが $MEMORY_DIR_BASH/ にある場合 → ロールバック後にファイルは残る(wake以降に作成されたもの) — warn: file <path> not in snapshot — not rolled back をログに記録

ロールバックのロック: ロールバック自体のロックは不要(レポートを読み書きしない)。ただし、現在の $MEMORY_DIR_BASH/ の競合を避けるため、実行中のwakeがある間はロールバックできない:

LOCK_DIR="$CWD_BASH/.wake-lock"
if [ -d "$LOCK_DIR" ]; then
  echo "⚠️ Wakeが現在実行中 — rollbackが競合する可能性があります。キャンセルするには 'stop' と入力。'continue' で強行(非推奨)"
  # Read user input — force continue or abort
fi
# Continue with rollback

決して rm しない — なぜか

  • delete → ファイルはTRASHに移動、クリアされたバージョンが残る
  • soft_delete → TRASHに移動
  • purge_trash → _archive/trash-purged-<date>/ に移動

唯一の例外はlock cleanup: rm -rf "$LOCK_DIR" — これはプロセス間調整用の一時的な空ディレクトリであり、ユーザーデータではない。

OS互換性

環境パス形式確認
Linux / macOS/home/user/.claude/...ネイティブ動作
Windows (Git Bash)/d/Projects/... → Win D:/Projects/...cygpath -w で変換、Git Bashで完全テスト済み
Windows (WSL)/mnt/d/Projects/...ネイティブ動作、Windowsパス変換なし
macOS (zsh)/Users/user/...ネイティブ動作

Windows固有の注意点

  • pwd -W はGit Bashでのみ利用可能(MSYS2)— 非Windowsではfailしないようにフォールバック
  • stat -c %Y はGit Bashで利用可能、macOSでは stat -f %m
  • パス計算のsed正規表現はいずれの環境でも動作:sed 's|[:/]|-|g'

Wakeのトリガーと引数

  • apply dream: wakeのエイリアス(skill handler経由)
  • wake: JSONを探し、なければユーザーにIDを尋ねる
  • wake all: レポート内のすべての提案を適用(確認あり)
  • wake <IDリスト>: カンマ区切りIDリスト(例 wake M1,M3,N2)
  • wake rollback [date]: 最新(または指定日付)のスナップショットに戻す

関連スキル