この記事はClaude Codeが実際の作業ログと実行記録をもとに下書きしました。

自分のメモをClaude Codeに検索させたいと思っていました。ところがOneNoteの .one は独自のバイナリ形式で、エージェントから見ればただのバイト列でしかありません。20年近く「マイ ノートブック さん @ 仕事」に書きためた26セクションが、手元にありながら参照できない状態でした。

そこでMarkdownへ移すことにしました。プレーンなテキストファイルなら grep で横断検索でき、当たりをつけたファイルだけを読み込ませれば済みます。結果として2,072ページと6,243個の画像などのアセット、合計4.8GBを抽出し、その後「メモ」という雑多な受け皿セクション(1,109ページ、全体の過半)も6つのトピックへ振り分けました。

実作業の大半はClaude Codeに任せましたが、要所では自分が判断しています。

抽出ツールの選定

最初にぶつかったのは、接続済みのMicrosoft 365コネクタが .one を読めないことでした。試すと application/msonenote というMIMEタイプを明示的に拒否します。Graph API経由で取得する onenote-md-exporter のようなツールもありますが、いずれもAzureアプリ登録が前提で、個人のメモを吸い出すには手続きが重くなります。

残った条件は「Azureアプリ登録が要らず、Markdownを直接吐く」の一点です。最初に選んだのはMicrosoft-OneNote-Exporter(enoola)でした。個人のMicrosoftアカウントでブラウザログインするだけでクラウドから直接取得でき、Obsidian互換のMarkdownと画像を階層付きで出力します。Windows、Mac、Linuxのどれでも動きます。

健全性で選び直す

ところが選定を確定させる直前、候補の比較をもう一度眺めていて引っかかりました。もう一方のone-note-to-markdown(segunak)のほうがスターが多く、最近も開発が動いている気配があります。GitHub APIで両方の数字を取ると、差ははっきりしていました。

one-note-to-markdown

★83、open issue 0件、48コミット

Microsoft-OneNote-Exporter

★4、open issue 5件(未解決)、73コミット

コミット数だけならMicrosoft-OneNote-Exporterが多くなっています。ただし5件のopen issueが未解決のまま止まっています。個人のメモを全部通すツールとしては、この差は無視できませんでした。

乗り換えには代償があります。one-note-to-markdownはOneNoteデスクトップアプリへのCOM Interop接続が必須で、Windows専用、WSLからは動かせません。しかもノートブックがローカルにある程度同期されていないと読めません。対象には4GB近い「投資.one」が含まれているので、同期待ちがどこまで伸びるか読めませんでした。Microsoft-OneNote-Exporterならブラウザログインだけで済み、この待ち時間は発生しません。

それでも後者を捨てました。同期待ちは一度きりのコストですが、メンテナが応答しないリポジトリを踏むコストは、壊れるたびに払うことになります。

判断のポイント

ツール選定でスター数だけを見るのは危険です。open issueの数、つまりメンテナが応答しているかどうかもあわせて見ることで、「動かなくなったときに直せるか」の見込みが立ちます。

実行前のセキュリティレビュー

GitHubから拾ってきたツールを、20年分の個人メモに向けて走らせます。ビルドする前に、ソースを一通り読みました。

  • ネットワーク通信コードは1行もありませんでした。HttpClient と WebClient を含めてリポジトリ全体を検索して確認しています。
  • プロセス起動は2箇所だけで、どちらも ArgumentList 経由のため、シェル解釈を経由しません。
  • パス生成を担う ExportPathSanitizer.cs には、パストラバーサル対策、Windows予約デバイス名対策、MAX_PATH対策が実装されています。
  • 同梱の node.exe(バージョン v26.8.1、103,747,400バイト)のSHA-256ハッシュは、Node.js公式配布の nodejs.org/dist/v26.8.1/SHASUMS256.txt と完全に一致しました。

最後のハッシュは、Claude Codeの確認をそのまま採らず、自分の端末でも Get-FileHash を回しました。ソース、メインビルド出力、テストビルド出力の3箇所すべてで一致しています。

WSLとWindowsのあいだで踏んだ地雷

変換そのものはGUIであっさり終わりました。詰まったのは、その結果をWSL側の作業ディレクトリへコピーする段階でした。

3フォルダだけが読めない

26セクションのうち3つ(_assets、メモ、アフィリエイト)だけ、WSLからディレクトリを列挙しようとすると EIO(errno 5)で落ちます。cp -r でも rsync でも同じでした。ところが単一ファイルの読み込みは通りますし、PowerShellからは何の問題もなく見えます。readdir と getdents64 だけがこの3フォルダに限って失敗するという、WSL2のDrvFs(/mnt/ 経由のWindowsドライブブリッジ)の不具合に行き当たっていました。

Claude Codeはここで粘りました。rsync --ignore-errors で部分転送を試し、robocopy を \\wsl.localhost\... へ向けて叩き、今度は無関係な ERROR_LOGON_FAILURE を拾ってきます。何周かしたところで、こちらから止めました。原因の特定はもう目的ではありません。

切り替えた判断

「動かない理由を厳密に特定する」より「動く経路に迂回する」ことを優先しました。3フォルダをWindows側でzipに固めてから単一ファイルとして転送する方式に変えたところ、ブリッジの不具合そのものを回避できました。

zip展開で当たった2つの問題

WSLには unzip が入っておらず、sudo apt install は方針上使いません。Pythonの zipfile で展開スクリプトを書きました。ここでも引っかかりました。

  • ENAMETOOLONG(errno 36):OneNoteのページタイトルをそのままファイル名にしているため、日本語タイトルが長いとext4のパス長制限(1コンポーネント255バイト)を超えます。200バイトを超えるパス構成要素をSHA-256でハッシュ短縮する処理を自作しました。これは奇しくも、one-note-to-markdown自身の ExportPathSanitizer.cs が採っているのと同じ発想です。
  • バックスラッシュ混入:PowerShellの Compress-Archive が、一部のZIPエントリ名に区切り文字として \ を残していました。ZIP仕様上のディレクトリ区切り / だけで分割すると階層が壊れるため、展開時に / と \ の両方で分割するよう直しました。

止まったコピーと二重ネスト

_assets のマージを cp -r 一発で回したら、特定の1ファイルで止まりました。/proc/<pid>/status の wchan が folio_wait_bit_common を指しています。デッドロックではなく本物のI/O待ちだと判断し、kill ではなくエージェント側のタスク停止機構で落としました。ついでに、引数の指定ミスで _assets/_assets/... という二重ネストができていたことも見つかったため、正しいパスで入れ直しています。

移行後の整理

見取り図をどう作るか

2,072ページを俯瞰するために INDEX.md を作りました。ここで選ばなかったのが、各ページをLLMで要約してインデックスに載せる方式です。2,072ページ分の要約生成はそれなりのコストになります。それに実際の探し方は、セクション名とタイトルで当たりをつけてから grep で絞り込み、引っかかったページだけを読むという手順で足りていました。結局 INDEX.md はセクションごとのタイトル一覧だけの、軽い構造索引にとどめています。

「メモ」を6つに割る

「メモ」セクションは20年分のブックマークや覚え書きが積み上がった受け皿で、1,109ページ、全体の過半を占めていました。キーワードベースの分類器を書き、6つのトピックへ振り分けました。

プログラミング・技術
573件(新セクション)
電子工作・ハードウェア
54件(新セクション)
投資・暗号通貨関連
34件(既存の「投資」「暗号通貨」セクションへ合流)
自動車
9件(新セクション)
健康
8件(新セクション)
語学
11件(新セクション)

残った420件はそのまま「メモ」に置いてあります。20年分の雑多なメモが機械的に全部きれいに分類できるほうが不自然で、これは想定どおりの結果です。

分類器が間違えた2件

分類結果は移動前に確認する前提で作りました。実際、2件の誤分類が出てきました。

  • ページタイトル「FX3」(USB 3.0コントローラチップ「EZ-USB FX3」を指す)が、単純な部分一致で「FX」という為替のキーワードに反応し、投資フォルダへ移されるところでした。
  • 「〇〇株式会社」という会社名の検索メモ3件が、「株式」への部分一致で投資フォルダに入っていました。

どちらも正規表現の否定先読み(株式(?!会社) など)を足してから、実際のファイル移動を流しています。分類器の出力は、動かす前に数件抜き出して目で見ないと信用できません。1,109件を一度に動かす操作で、この手間を省く理由はありませんでした。