【ctx】Syncthingで2台のPCのエージェント履歴を自動同期する
WSL2 とミニPC(minis)のどちらで Claude Code や Codex を使っても、会話の履歴が相手のPCに自動で届くようにした。両方のPCの ctx で、両方の履歴を検索できる。
ひとことで言うと Syncthing で元のログをお互いのPCへコピーし続け、ctx にはそのコピーも読ませている。
登場するもの #
| 名前 | 役割 |
|---|---|
| ctx | Claude Code や Codex の会話履歴を、手元で検索できるツール |
| 元のログ | Claude Code や Codex が会話ごとに書き出すファイル。ctx はこれを読む |
| Syncthing | PC 同士でフォルダを直接同期するツール |
| Tailscale | 離れた PC 同士をつなぐ仮想 LAN。Syncthing はこの中だけで通信する |
| WSL2 | これまでのメイン環境。Windows 上の Ubuntu |
| minis | これからのメイン環境。ミニPC の Ubuntu |
全体像 #
実線は、そのPCのログをそのまま読む線。点線は、Syncthing で相手のPCに運んだコピーを読む線。
ルールは3つだけ。
- 自分のログは送るだけ、相手のログは受け取るだけ。 両方から同じファイルを書き換えないので、競合しない。
- 元のPCで消えても、コピーは消さない。 Claude Code は30日より古いログを消すが、相手のPCには残る。
- ctx はコピーも普通の履歴として読む。 ふだんの検索にも日報にも、両方のPCの分が出る。
使い方 #
ふだんどおり検索すれば、両方のPCの履歴が出る。
ctx search "検索したい言葉"どちらのPCで使った分かを絞るときは、グループを指定する。
ctx search "検索したい言葉" --source-group minis # minis の分だけ
ctx search "検索したい言葉" --source-group torrent-nano-wsl2 # WSL2 の分だけ日報づくりで使う ctx list events も、設定を変えずに両方のPCの分を返す。
2026-09-05 以前の履歴 #
この期間は元のログがもう無いので、Syncthing では運べない。minis には、ctx の書き出し機能(archive)で別の場所に入れてある。検索するときは、置き場所を指定する。
ctx --data-root ~/ctx-archive/torrent-nano-wsl2 search "検索したい言葉"どこに何があるか #
| もの | WSL2 | minis |
|---|---|---|
| 自分のログ | ~/.claude/projects、~/.codex/sessions | 同左 |
| 相手のログのコピー | ~/ctx-mirror/minis/ | ~/ctx-mirror/torrent-nano-wsl2/ |
| Syncthing の設定 | ~/.config/syncthing/ | ~/.local/state/syncthing/ |
| 2026-09-05 以前の履歴 | ctx の中 | ~/ctx-archive/torrent-nano-wsl2/ |
届くまでの時間 #
| 場面 | 目安 |
|---|---|
| ふだんの追記 | 30秒ほど。ctx にもすぐ反映 |
| 初回のコピー(約830MB) | 約5分 |
| 片方の電源が切れていた | 両方が動いたときに追いつく |
WSL2 と minis は、Tailscale の中継サーバー経由でつながっている。そのため大きな転送は遅いが、ふだんの追記なら困らない。
正常か確かめる #
相手のPCとつながっているか(どちらのPCでも同じ)
syncthing cli show connections | jq '.connections[] | select(.connected) | .address'相手のアドレスが1行出れば正常。何も出ないときは、相手のPCの電源と Tailscale を確かめる。
ctx がコピーを読めているか
ctx sources相手の分の取り込み元が available なら正常。名前は次のとおり。
| PC | 相手の分の名前 |
|---|---|
| WSL2 | minis-claude、minis-codex |
| minis | torrent-nano-wsl2-claude、torrent-nano-wsl2-codex |
画面で見たいときは、minis の本体のブラウザで http://127.0.0.1:8384 を開く。フォルダがすべて「最新」なら同期済み。
やってはいけないこと #
.stfolderを消さない。~/.claude/projectsと~/.codex/sessionsの中にある、Syncthing の目印。消すと同期が止まる。- コピー先にある空のファイルを消さない。
~/ctx-mirror/<相手>/codex/のarchived_sessionsとhistory.jsonlのこと。無いと ctx がエラーを出す。 - コピーを
~/.claude/projectsに置かない。 Claude Code 自身の履歴と混ざり、30日で消される。
よく出る表示 #
ctx import --all を実行すると、どちらのPCでも「2件失敗」と出る。どちらも同期とは関係ない、もとからある問題なので、放っておいてよい。
- サブエージェントのログが symlink になっていて、ctx が読まない
- Codex のログ1件に2つのセッション情報が入っていて、ctx が保留にしている
ほかの履歴の取り込みには影響しない。
なぜこの方法にしたか #
ほかに3つの方法を比べた。日報づくりも含めて、両方のPCの分をふだんどおり扱えるのはこの方法だけだった。
| 方法 | 結果 |
|---|---|
| ctx の書き出しと復元(archive) | 一度きりの移行向き。別の置き場所になり、ふだんの検索に混ざらない。重ねて復元すると衝突する |
| ctx のサーバー機能(beta) | 別のPCから読めるのは検索と表示だけで、list events は読めない。版合わせも要る |
| rsync と Tailscale SSH | 自動で回すには SSH の再認証をやめる必要があり、端末ごとにも絞れない |
| Syncthing と ctx の追加の置き場所(採用) | SSH を緩めずに済み、ふだんの ctx に混ざり、すぐ届く |
付録:構築手順 #
作り直すときのメモ。WSL2 は Syncthing 1.18、minis は 1.27 で動かしている。
1. Syncthing を入れて起動する #
両方のPCで入れる。dotfiles の etc/packages.list にも追加してある。
sudo apt install -y syncthing既定の共有フォルダを作らずに初期設定を作り、ログイン時に起動するようにする。
# WSL2(1.18)
syncthing serve --generate="$HOME/.config/syncthing" --no-default-folder
# minis(1.27)
syncthing generate --no-default-folder
# 両方
systemctl --user enable --now syncthing.serviceminis は起動時に自動ログインする設定なので、再起動しても Syncthing が動く。
2. Tailscale の中だけで通信させる #
公開の探索サーバーと中継サーバーを使わない。クラッシュ報告と使用統計も送らない。
for o in global-ann-enabled local-ann-enabled relays-enabled natenabled crenabled; do
syncthing cli config options "$o" set false
done
syncthing cli config options uraccepted set -- -13. 相手のPCとフォルダを登録する #
syncthing cli config devices add --addresses は、両方の版で異常終了した。そこで Syncthing の API で登録する。まとめて送ると400エラーになるので、1件ずつ送る。
# 設定ファイルは 1.18 なら ~/.config/syncthing、1.27 なら ~/.local/state/syncthing にある
K=$(sed -n 's@.*<apikey>\(.*\)</apikey>.*@\1@p' ~/.config/syncthing/config.xml)
post() {
curl -fsS -X POST "http://127.0.0.1:8384$1" \
-H "X-API-Key: $K" -H 'Content-Type: application/json' -d "$2"
}
# 自分のデバイスIDを調べる
syncthing cli show system | jq -r .myID
# 相手のPC。アドレスは Tailscale の名前で直接書く
post /rest/config/devices '{
"deviceID": "<相手のID>",
"name": "minis",
"addresses": ["tcp://minis.<tailnet>.ts.net:22000"]
}'
# 自分のログは送るだけ
post /rest/config/folders '{
"id": "ctx-claude-torrent-nano-wsl2",
"path": "/home/<ユーザー>/.claude/projects",
"type": "sendonly",
"devices": [{"deviceID": "<自分のID>"}, {"deviceID": "<相手のID>"}]
}'
# 相手のログは受け取るだけで、消さない
post /rest/config/folders '{
"id": "ctx-claude-minis",
"path": "/home/<ユーザー>/ctx-mirror/minis/claude/projects",
"type": "receiveonly",
"ignoreDelete": true,
"devices": [{"deviceID": "<自分のID>"}, {"deviceID": "<相手のID>"}]
}'Codex も同じ形で登録する。フォルダ ID は両方のPCでそろえる。
| フォルダ ID | 送る側 | 受ける側 |
|---|---|---|
ctx-claude-torrent-nano-wsl2 | WSL2 の ~/.claude/projects | minis の ~/ctx-mirror/torrent-nano-wsl2/claude/projects |
ctx-codex-torrent-nano-wsl2 | WSL2 の ~/.codex/sessions | minis の ~/ctx-mirror/torrent-nano-wsl2/codex/sessions |
ctx-claude-minis | minis の ~/.claude/projects | WSL2 の ~/ctx-mirror/minis/claude/projects |
ctx-codex-minis | minis の ~/.codex/sessions | WSL2 の ~/ctx-mirror/minis/codex/sessions |
4. ctx にコピーを読ませる #
WSL2 での例。minis では minis を torrent-nano-wsl2 に読み替える。
# Codex は archived_sessions と history.jsonl が無いとエラーになるので、空のものを置く
mkdir -p ~/ctx-mirror/minis/codex/archived_sessions
touch ~/ctx-mirror/minis/codex/history.jsonl
ctx sources add minis-claude --provider claude --root ~/ctx-mirror/minis/claude --source-group minis
ctx sources add minis-codex --provider codex --root ~/ctx-mirror/minis/codex --source-group minisあとは ctx の常駐プロセスが自動で取り込む。
まだやっていないこと #
- 2026-05-27〜08-11 の Claude Code の履歴は、旧版 ctx(0.19)のバックアップにしか無い
- Claude Code のプロジェクトごとのメモリは、minis に移していない
- Claude Code の30日削除は止めていない