0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Code セッション終了毎にセッションログをテキストファイルへ書き出す

0
Last updated at Posted at 2026-08-01

環境

  • Ubuntu Linux 24.04LTS
  • Claude Code

何か

Claude Code のセッション終了のたびに、当該セッションログ(~/.claude/projects/<project>/<session-id>.jsonl)を、
プレーンテキストに変換して書き出します。

もともとは Evernote のノートに流し込みたくて、
クリップボード経由や、 msmtp等とEvernote のメール転送機能(xxxx@m.evernote.com 宛にメールを送るとノートになる機能)を使う想定でしたが、
メール本文に直接書いても添付にしても改行が消えてしまい実用にならなかったため、
代わりに「テキストファイルとして書き出し、Evernote 側で手動で取り込む」という運用にしています。

できること

  • Claude Code の SessonEnd (/logout) ごとに当該セッションIDをファイル名に含んだファイルを /tmp に書き出す。
  • JSONなのでプレーンテキストに変換してから書き出す。
  • 同じセッションの場合は黙って上書き。

機能詳細

  • claude-log-to-txt.py — 変換本体。標準入力から Claude Code のセッションログ(JSONL)を読み、1行目にタイトル・空行を挟んで書き起こし本文を続けた、整形済みプレーンテキストを標準出力に書きます。副作用の無い純粋なフィルタです。
  • claude-log-to-txt.sh — 上記スクリプトをラップし、標準出力に結果を流しつつ、同じ内容を /tmp/claude-log-<session-id>.txt にも保存します。同名ファイルが既にあれば黙って上書きします。
  • SessionEnd hook との連携 — Claude Code の SessionEnd hook から自動起動できる設定例(claude-log-settings.json)を同梱しています。これを使うと、セッション終了のたびに自動でテキストファイルが /tmp 配下に保存されます。

コード

claude-log-to-txt.py

claude-log-to-txt.py
# -*- coding: utf-8 -*-
"""claude session log to text

   - claude session log (jsonl) to plane text.
   - claude session log from stdin.
   - session title is 1 line, blank line, folllow body.
   - to stdout
"""
import json, sys
from datetime import datetime, timezone

title = None
body = []
for line in sys.stdin:
    d = json.loads(line)
    role = d.get('type')

    if role == 'ai-title' and title is None:
        title = d.get('aiTitle')
        continue

    if role in ('user', 'assistant'):
        msg = d.get('message', {})
        content = msg.get('content')

        ts = d.get('timestamp')
        if ts:
            dt = datetime.fromisoformat(ts.replace('Z', '+00:00')).astimezone()
            ts_str = dt.strftime('%Y-%m-%d %H:%M:%S')
        else:
            ts_str = '?'

        if isinstance(content, str):
            body.append(f'[{ts_str}] [{role}] {content}\n')
        elif isinstance(content, list):
            for c in content:
                ctype = c.get('type')
                if ctype == 'text':
                    body.append(f'[{ts_str}] [{role}] {c["text"]}\n')
                elif ctype == 'tool_use':
                    name = c.get('name')
                    tool_input = json.dumps(c.get('input', {}), ensure_ascii=False, indent=2)
                    body.append(f'[{ts_str}] [{role}] tool_use: {name}\n{tool_input}\n')
                elif ctype == 'tool_result':
                    result_content = c.get('content')
                    if isinstance(result_content, list):
                        result_text = '\n'.join(
                            rc.get('text', '') for rc in result_content
                            if isinstance(rc, dict) and rc.get('type') == 'text'
                        )
                    else:
                        result_text = result_content or ''
                    body.append(f'[{ts_str}] [{role}] tool_result:\n{result_text}\n')

# 1行目にタイトル、空行を1行挟んでから続きを書く
print(title or '')
print()
for entry in body:
    print(entry)

claude-log-to-txt.sh

claude-log-to-txt.sh
#!/bin/bash
# claude-log-to-txt.py をラップし、stdout に整形済みテキストを流しつつ
# 同じ内容をテンポラリファイルにも保存する。
# stdout をそのまま msmtp にパイプできるよう、保存先パスは stderr に出す。
# 第1引数にセッションIDを渡すと /tmp/claude-log-<session-id>.txt に保存する
# (同名ファイルがあれば黙って上書き)。省略時はタイムスタンプ付きファイル名にする。
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
session_id="${1:-}"
if [ -n "$session_id" ]; then
    outpath="/tmp/claude-log-${session_id}.txt"
else
    outpath="/tmp/claude-log-$(date +%Y%m%d-%H%M%S).txt"
fi

python3 "$SCRIPT_DIR/claude-log-to-txt.py" | tee "$outpath"

echo "saved: $outpath" >&2

claude-log-settings.

  • 実際には ~/.claude/settings.json に配置される。
  • また、起動するスクリプトは下記では ~/bin に配置される
claude-log-settings.json
{
  "hooks": {
    "SessionEnd": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.session_id, .transcript_path' | { read -r sid; read -r f; \"$HOME/bin/claude-log-to-txt.sh\" \"$sid\" < \"$f\"; } 2>/dev/null || true"
          }
        ]
      }
    ]
  },
  "theme": "dark"
}

設定方法

SessionEnd hook 経由で自動変換するようにする。

a. claude-log-to-txt.sh と claude-log-to-txt.py を PATH の通った場所に配置します。この例では ~/bin/ にコピーする運用にしています。

  ```bash
  cp claude-log-to-txt.sh claude-log-to-txt.py ~/bin/
  ```

b. リポジトリ内の claude-log-settings.json の hooks.SessionEnd の内容を、実際の ~/.claude/settings.json にマージします。例えば以下です。

  ```json:settings.json
  {
    "hooks": {
      "SessionEnd": [
        {
          "hooks": [
            {
              "type": "command",
              "command": "jq -r '.session_id, .transcript_path' | { read -r sid; read -r f; \"$HOME/bin/claude-log-to-txt.sh\" \"$sid\" < \"$f\"; } 2>/dev/null || true"
            }
          ]
        }
      ]
    }
  }
  ```

使い方

  • hook を設定していれば、Claude Code のセッションが終了するたびに自動で /tmp/claude-log-<session-id>.txt が生成されます。同じセッションを resume, continue した場合は同じセッションIDのファイルに黙って上書きします。

  • 直接実行(標準出力のみ):

    python3 claude-log-to-txt.py < ~/.claude/projects/<project-dir>/<session-id>.jsonl
    
  • ラッパー(teeで標準出力 + /tmp への保存):

    ./claude-log-to-txt.sh <session-id> < ~/.claude/projects/<project-dir>/<session-id>.jsonl
    

    セッション ID を省略するとタイムスタンプ付きのファイル名(/tmp/claude-log-YYYYMMDD-HHMMSS.txt)になります。

注意

Claude Code のセッションログ形式は保証されてないので変更があると使えなくなります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?