M.

Claude Code の会話ログをブログのネタ帳にする(jsonl から体験を掘り出す)

このブログでは「自分の体験・データを軸に書く」と決めています。ところが、体験はすぐに忘れます。「夜中に PC がスリープしてジョブが止まった」ことは覚えていても、何時に止まったのか、どのコマンドで直したのかは思い出せません。

そこで役に立つのが、Claude Code の会話ログ です。Claude と一緒にやった作業は、頼んだ文面も、実行したコマンドも、ログに残っています。

このブログでも、次の記事は会話ログから材料を集めて書きました。

環境:Windows 10 / Git Bash / Python 3 / Claude Code 2.1.302

ログはどこにあるか

会話ログは ~/.claude/projects/<プロジェクト>/<セッション>.jsonl にあります。プロジェクトのフォルダ名は、作業ディレクトリのパスの記号を - に置き換えたものです(例:C--Users-me-Desktop-repos-mori-portfolio)。

1行に1件の JSON が入っています。使うのは主に次の3種類です。

種類どこを見るか中身
自分の発言message.role が user で、content が文字列か type: "text"頼んだ文面
Claude の発言message.role が assistant で、type: "text"説明・報告
ツールの呼び出しtype: "tool_use" の input実行したコマンド、書いたファイル

各行には timestamp(UTC)も付いているので、「いつ何をしたか」がそのまま分かります。

ログは既定で30日で消えます。書きたいネタがあるなら、早めに掘るのが大事です(期間は cleanupPeriodDays で変えられます)。

まず grep で当たりをつける

最初は、キーワードでどのセッションに材料があるかを探します。

cd ~/.claude/projects && grep -l -i "SetSuspendState\|スリープ" */*.jsonl

これでファイルの一覧が出ます。ただ、jsonl を直接読むのは大変です。1行が数千文字あることも珍しくありません。

必要なところだけを抜き出す

そこで、キーワードを含む「自分の発言」「Claude の発言」「ツールの呼び出し」だけを、時刻つきで短く抜き出す Python スクリプトを Claude に書いてもらいました。

import json, glob, os, re

root = os.path.expanduser("~/.claude/projects")
pat = re.compile(r"SetSuspendState|スリープ", re.I)

for f in sorted(glob.glob(os.path.join(root, "*", "*.jsonl"))):
    hits = []
    with open(f, encoding="utf-8", errors="replace") as fh:
        for line in fh:
            if not pat.search(line):
                continue
            d = json.loads(line)
            ts = d.get("timestamp", "")
            msg = d.get("message") or {}
            role = msg.get("role")
            content = msg.get("content")
            items = content if isinstance(content, list) else [{"type": "text", "text": content}]
            for it in items:
                if not isinstance(it, dict):
                    continue
                if it.get("type") == "text" and pat.search(str(it.get("text"))):
                    who = "USER" if role == "user" else "AI"
                    hits.append(f"[{ts}] {who}: {str(it['text'])[:300]!r}")
                elif it.get("type") == "tool_use":
                    s = json.dumps(it.get("input"), ensure_ascii=False)
                    if pat.search(s):
                        hits.append(f"[{ts}] TOOL: {s[:400]}")
    if hits:
        print("==", os.path.relpath(f, root))
        print("\n".join(hits[:25]))

ポイントは次のとおりです。

  • ツールの結果(tool_result)は拾わない。コマンドの出力や読んだファイルの中身が入っていて、量が多いうえに、関係のない内容まで混ざります
  • 文字数を切る(300字・400字)。全体の流れが分かれば十分で、細部はあとで該当箇所だけ読みます
  • 時刻を残す。記事に「夜中の3時」「約30分後」と書けるのは、時刻があるからです

スリープの記事では、これで「画像生成が781枚目で止まっていた」「スリープ防止のスクリプトが3日間残っていた」「イベントログで 03:04 にスリープしたと確かめた」といった、忘れていた具体的な出来事を拾えました。

つまずいたこと

auto mode に止められた

最初にこのスクリプトを実行しようとしたら、auto mode に止められました。理由は「PII Data Handling」(個人情報の扱い)です。

会話ログには、作業中に読んだファイルの中身やメールアドレスなど、いろいろなものが入っています。全セッションのログをまとめて読み出す操作が、個人情報をかき集める動きに見えたのだと思います。

止められたあと、Claude は回避策を探さずに、何をしようとしていたのかを説明して確認を求めてきました。「スリープに関する部分だけを抜き出し、記事に使うのはコマンドと流れだけ」と確かめてから許可すると、実行できました。

自分のログとはいえ、まとめて読ませるのは強い操作です。止めてもらえるのは安心材料だと思っています。

Windows で文字化け・エラー

許可したあと、今度はスクリプトがエラーで落ちました。

UnicodeEncodeError: 'cp932' codec can't encode character '�'

Windows の Python は、標準出力を cp932(Shift_JIS 系)で書こうとします。ログの中に cp932 で表せない文字があると、そこで落ちます。

実行するときに PYTHONIOENCODING=utf-8 を付けると直ります。

PYTHONIOENCODING=utf-8 python3 extract.py > out.txt

出力が長くなるので、ファイルに書き出してから grep で読むのがおすすめです。

記事にするときに気をつけていること

ログには、記事に載せてはいけないものも入っています。

  • サーバーの IP・プロジェクト ID・鍵のパス:コマンドの中にそのまま入っています。記事では伏せます
  • 非公開リポジトリの名前や中身:手法として一般化して書きます
  • 仕事の作業:家の作業だけを使います

それから、ログの説明をそのまま信じない ことも大事です。Claude の「〜が原因でした」という説明は、そのときの推測のこともあります。スリープの記事では、ログでは「どうしてスリープ防止が残ったのか」までは分かりませんでした。起動したときのコマンドを見て、PID を渡さずに起動していたことを確かめてから書きました。

まとめ

  • Claude Code の会話ログには、頼んだこと・実行したコマンド・時刻が残っていて、体験記事の材料になる
  • 30日で消えるので、書きたいネタは早めに掘る
  • grep で当たりをつけ、発言とツール呼び出しだけを短く抜き出す。ツールの結果は拾わない
  • まとめて読み出すと auto mode に止められることがある。目的と範囲を確かめてから許可する
  • Windows では PYTHONIOENCODING=utf-8 を付ける

参考文献

この記事をシェア

関連する記事

YouTube への動画アップロードを API で自動化し、OAuth クライアントを複数のアプリで使い回す

自作アプリの紹介動画を、YouTube Data API で予約投稿しています。OAuth クライアントは1つだけ作って全アプリで共有し、トークンはアプリごとに分けました。クォータ(1日10,000ユニット)の範囲で何本まで上げられるか、二重アップロードの防ぎ方、Claude Code に覚えさせた置き場所のルールをまとめます。

Alexa-hosted スキルのビルドが jest で落ちた件と、ログを直接読めない環境でエラーを集計する方法

Alexa スキル「安眠ノイズ」に Jest のテストを足したら、Alexa-hosted のビルドが失敗するようになりました。原因の切り分けと、テストを lambda/ の外に出した構成、さらに CloudWatch Logs に直接アクセスできない Alexa-hosted で、エラーを Logs Insights で集計できる1行ログにした話をまとめます。

コード進行アプリの楽譜表示を自作した(大譜表・コード名どおりの綴り・転調で調号を変える)

コード進行生成アプリ Chord Eureka の楽譜表示を、html-midi-player(Magenta)の表示から、SVG を直接組み立てる自作の大譜表に置き換えました。E♭m がシャープで書かれる、進行によって音部記号が変わるといった問題をどう直したかと、置き換えるかどうかの判断をまとめます。

コード進行アプリにボイシングのプリセットを10種類足した(Drop 2・シェル・4度堆積など。既定の音は1バイトも変えない)

コード進行生成アプリ Chord Eureka に、Drop 2・シェル・ルートレス・4度堆積などのボイシングを選べる機能を足しました。既定の音を変えて一度戻した経緯、「書かれていない音は足さない」という決まり、各プリセットの組み立て方をまとめます。

テーマから探す