Metadata-Version: 2.4
Name: claude-session-sync
Version: 0.3.0
Summary: Sync Claude Code sessions across Windows, macOS, and Linux
Project-URL: Homepage, https://github.com/tsubome/claude-session-sync
Project-URL: Issues, https://github.com/tsubome/claude-session-sync/issues
Project-URL: Repository, https://github.com/tsubome/claude-session-sync
Author: tsubome
License-Expression: MIT
License-File: LICENSE
Classifier: Environment :: Console
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development
Requires-Python: >=3.9
Description-Content-Type: text/markdown

[日本語](docs/README_ja.md) | English

# claude-session-sync

![Python 3.9+](https://img.shields.io/badge/python-3.9%2B-blue)
![License: MIT](https://img.shields.io/badge/license-MIT-green)

## What is this?

**claude-session-sync** is a CLI tool that syncs [Claude Code](https://docs.anthropic.com/en/docs/claude-code) session history across Windows, macOS, and Linux.

- Continue any conversation on any machine — pick up exactly where you left off
- Uses a **private GitHub repository** as the sync backend (no third-party servers)
- **Automatic path conversion**: OS-specific paths are replaced with portable placeholders (e.g., `/home/user/projects` → `{{PROJECTS}}` → `C:\projects`)

## How it works

```
Ubuntu                         GitHub                          Mac
claude-session-sync push  →  Private Repo  →  claude-session-sync pull
/home/user/projects       →  {{PROJECTS}}  →  /Users/user/projects
```

Session files (`.jsonl`) are stored under `~/.claude/projects/` by Claude Code. This tool copies them into a private GitHub repository, translating machine-specific paths to shared placeholders on push, and back to local paths on pull.

Memory files stored under `~/.claude/projects/*/memory/` are also synced.
All machines share a single set of memory files — the last push becomes the source of truth.
On pull, local memory is completely replaced with the shared version.
Changes are tracked through git commit history.

## Features

- **Cross-machine session resume** — open any session from any registered machine
- **Automatic path conversion** with user-defined placeholders
- **Session locking** — prevents two machines from editing the same session simultaneously
- **Background daemon** — periodic push backup while Claude Code is running
- **Selective sync** — only sessions under configured directories are shared
- **Windows / macOS / Linux** support
- **Memory & CLAUDE.md sync** — project memory files and global CLAUDE.md are synced across machines automatically during push/pull
- **Shared memory model** — all machines use the same memory files, git tracks change history
- **git push retry** — automatic pull-and-retry (up to 3 times) when push is rejected due to concurrent updates
- **Duplicate daemon prevention** — the resume command checks for existing daemons before starting a new one
- **Last-editing machine display** — the session list shows which machine last edited each session, not just where it was created

## Quick Start

```bash
# Install
pip install claude-session-sync
```

### Development install

```bash
# Development install
git clone https://github.com/tsubome/claude-session-sync.git
cd claude-session-sync
pip install -e .
```

```bash
# Setup — first machine (creates a new private GitHub repo)
claude-session-sync init

# Setup — additional machines (connects to the existing repo)
claude-session-sync init

# Daily usage — `ccsync` is a short alias for `claude-session-sync`
ccsync resume
# Pulls the latest sessions, lets you pick one interactively,
# launches Claude Code, then pushes and releases the lock on exit.
```

## Commands

| Command | Description |
|---|---|
| `resume [SESSION_ID]` | **Main command.** Pull → select session interactively → launch Claude Code → push + release lock on exit. Pass `SESSION_ID` to skip the list. |
| `resume --latest` | Automatically selects the most recently updated session. |
| `resume --from MACHINE_ID` | Show only sessions from a specific machine. |
| `resume --all` | Show all sessions, ignoring `sync_directories` filter. |
| `init` | Register this machine and create or connect to the shared GitHub repository. |
| `push [--dry-run]` | Manually push local sessions to the remote repository. |
| `pull [--dry-run] [--force]` | Manually pull sessions from the remote repository. |
| `update` | Push sessions and release any locks left behind after an abnormal exit. |
| `status` | Show the current sync status (last push/pull time, machine ID, etc.). |
| `list [--remote] [--format table\|json]` | List local (or remote) sessions. |
| `lock show` | Show all current locks. |
| `lock release [SESSION_ID]` | Release a lock. Omit `SESSION_ID` to release all locks on this machine. |
| `lock cleanup` | Delete all expired locks. |
| `config show` | Show the current configuration. |
| `config add-placeholder NAME=PATH` | Add a new placeholder mapping for this machine. |
| `config set-path NAME MACHINE_ID PATH` | Set a path for a specific machine in `shared_placeholders.json`. |
| `daemon [--interval SECONDS] [--push-only] [--stop]` | Run a background sync daemon (default interval: 300 s / 5 min). |

## Configuration

The local config file is stored at `~/.claude-session-sync/config.json`.

Placeholder mappings shared across all machines are stored in the GitHub repository as `shared_placeholders.json`.

### Example config

```json
{
  "machine_id": "ubuntu-work",
  "github_owner": "your-username",
  "github_repo": "claude-sessions",
  "sync_directories": [
    "/home/your-username/projects"
  ],
  "custom_placeholders": {
    "PROJECTS": "/home/your-username/projects"
  }
}
```

`sync_directories` controls which sessions are visible in `resume`. Only sessions whose working directory falls under one of these paths are shown. Sessions outside them are ignored unless you pass `--all`.

## Custom Placeholders

Placeholders let the same session be opened on machines with different filesystem layouts.

**Adding during init:**

```bash
claude-session-sync init --add-placeholder PROJECTS=/home/user/projects
```

**Adding afterwards:**

```bash
claude-session-sync config add-placeholder PROJECTS=/home/user/projects
```

**Setting the path for another machine:**

```bash
claude-session-sync config set-path PROJECTS macbook /Users/user/projects
claude-session-sync config set-path PROJECTS windows C:\projects
```

When the same session is pulled on macOS, `{{PROJECTS}}` is automatically expanded to `/Users/user/projects`. On Windows it becomes `C:\projects`.

## Session Locking

When you resume a session, `claude-session-sync` acquires a lock in the shared repository so that no other machine can open the same session at the same time.

| Detail | Value |
|---|---|
| Lock TTL | 10 minutes (default) |
| Heartbeat | Background daemon refreshes the lock while Claude Code is running |
| Crash recovery | Locks auto-expire after TTL — no manual cleanup needed in most cases |
| Manual release | `claude-session-sync lock release` |

If a session is locked by another machine, you are shown a warning and asked whether to take over the lock. This is safe if the other machine crashed or was closed without a proper exit.

## Concurrent Operation

Multiple machines can work on **different** sessions simultaneously.
Each session has its own lock, so editing CrossClip on Linux while editing WhisperApp on Windows is fully supported.

If two machines push at the same time, the tool automatically retries with pull-and-push (up to 3 attempts).

## Troubleshooting

**"Session is locked by another machine"**

The previous Claude Code session likely exited abnormally. You can:

1. Select the locked session → confirm the takeover prompt (`y`)
2. Or run `claude-session-sync update` on the machine that holds the lock (if still reachable)
3. Or run `claude-session-sync lock release SESSION_ID` to force-release it

**"No sessions found"**

Run `claude-session-sync pull` first to download sessions from the remote repository, then try `resume` again.

**Windows: daemon does not stop**

The daemon uses a stop-file mechanism on Windows (instead of signals). Run `claude-session-sync daemon --stop` to request a graceful shutdown.

**Sessions from another machine are not visible**

Make sure `sync_directories` on both machines point to the same placeholder (e.g., both mapped to `{{PROJECTS}}`). Run `claude-session-sync config show` to verify, and use `config set-path` to add missing machine entries.

## Requirements

- Python 3.9+
- Git
- [GitHub CLI (`gh`)](https://cli.github.com/) — must be authenticated (`gh auth login`)
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code)

## License

MIT
