Skip to content

Repository files navigation

claude-toudou

Persistent memory and session continuity for Claude Code across multiple machines.

Run Claude Code on your home PC and office PC — and, optionally, an always-on hub that keeps them in sync while you're away. Switch between machines, or run them at the same time, without losing context. No dedicated database. Just git, Node.js, and a CLAUDE.md.

v2: nodes may now run concurrently (not only in shifts), and you can add an optional always-on hub node. Safety comes from a strict pull-before-push rule plus per-node ownership and in-progress guards. See Concurrency & the hub.

Use a private git repository. The relay file contains your work context and task details. Never use a public repo with this setup.


What This Is

You run Claude Code on two machines — home and office, laptop and desktop. Every time you switch computers, Claude starts cold. No memory of what it was doing. No memory of the other machine.

claude-toudou gives Claude Code persistent memory across machines by turning the two instances into a single agent that works in shifts.

When one machine's session ends, its Claude writes a structured handoff note. The other machine's Claude reads it, understands the intent, and continues without backtracking.

[home PC]                              [office PC]
    │                                       │
  Claude works                              │
  Session ends                              │
    │                                       │
  writes handoff ──── git push ──────────►  │
  "decisions made,                          │
   tasks pending,                           │
   what to do next"                         │
                                     git pull
                                     Claude reads, understands, continues
                                            │
                                     writes reply ─── git push ──► [home PC]

In v1 the instances ran strictly in shifts. In v2 they may run concurrently — and an optional always-on hub can keep every machine current even while the others are off. What makes concurrency safe is the pull-before-push rule, not turn-taking.


v2: Concurrency & the hub

Pull before push, always. A bare git push only sends your commits; it never pulls in another node's work. Skip the pull and you eventually fork the relay file and your memory — the exact failure mode v2 is built to prevent. Every sync, manual or scheduled, must run:

git pull --rebase --autostash   →   commit   →   push   (retry once on rejection)

Use the included helper so you can't forget:

scripts/sync.sh                 # Linux/macOS — pull-first commit & push
scripts/sync.ps1                # Windows (PowerShell) — same, path-independent

It pulls first, commits, pushes, retries once if another node pushed in between, and skips itself if a sync is already running or the repo is mid-rebase/merge.

The optional hub. A spare always-on machine — home server, SBC, NAS, or an idle laptop — runs scripts/sync.sh on a schedule (a few times a day, not constant polling) so every node stays current without anyone being at a keyboard. The hub is just another node: same pull-first rule, tags its own lines like everyone else. Add it to the hostname table and a cron entry; nothing else changes.


Who This Is For

You need all of the following:

  • Claude Code on two machines (home + office is the typical setup)
  • You switch computers regularly and want session continuity
  • Basic git skills (commit, push, pull)
  • Node.js ≥ 18 on both machines
  • Optional: a Telegram bot for cross-machine notifications

If you use Claude Code on one machine only, you don't need this.

Common search terms that led here: claude code multiple machines, claude code cross machine memory, claude code session continuity, claude code switch computers, claude code persistent context, claude code two computers


What It Solves

Problem 1: Switch computers → context lost

Without this: every time you switch machines, Claude starts from zero. With this: Claude reads the handoff note and continues where it left off.

Problem 2: Shared Telegram bot → accidental sends

Both instances share one Telegram bot. Either could send to your phone at any time. This project keeps silence as the default: a desktop session sends nothing to Telegram unless Claude explicitly calls notify-telegram.js, which queues the message for delivery via GitHub Actions. No explicit call = no send, always.

Problem 3: Routines (Web) can't reach Telegram directly

Claude Code Routines run on Anthropic's servers, which block outbound connections to api.telegram.org. Direct curl calls silently fail. This project routes notifications through GitHub Actions — Claude pushes a pending file to GitHub, Actions picks it up and sends the message. Works from any environment, including when your PC is off.

Problem 4: Compaction amnesia

Long sessions get compressed. Earlier context is lost. The included PreCompact hook injects 10 rules before each compression: extend prior summaries, never replace them.


⚠️ Windows Users

python3 may be a Microsoft Store stub that silently fails in non-interactive contexts (Task Scheduler, Claude Code hooks, shell scripts without a terminal).

Check which python3 you have:

(Get-Command python3).Source
# Bad:  C:\Users\<user>\AppData\Local\Microsoft\WindowsApps\python3.exe  ← Store stub
# Good: C:\Users\<user>\AppData\Local\Programs\Python\Python312\python.exe

Recommended fix: Use the Node.js Telegram sender instead — it works reliably on Windows without any path configuration:

node scripts/telegram/send-telegram.js "your message"

If you are behind a corporate proxy with a custom root CA, add --use-system-ca (Node.js ≥ 22) so Node trusts the Windows certificate store.

If you need Python, use the full absolute path to python.exe (not python3). The setup script will warn you automatically if a stub is detected.


Quick Start

Your relay repo must be private (it will contain your work context), so first create an empty private repository on GitHub (e.g. my-claude-relay), then:

git clone https://github.com/Zhangshuzz/claude-toudou.git my-claude-relay
cd my-claude-relay
git remote set-url origin https://github.com/YOUR_NAME/my-claude-relay.git
git push -u origin main
npm run setup

npm run setup asks a few questions (machine names, hostnames) and outputs the exact JSON to add to your settings file. That's the hardest part done.


Full Setup (5 steps)

1. Clone into your own private repo and install

Create an empty private repository on GitHub first, then:

git clone https://github.com/Zhangshuzz/claude-toudou.git my-claude-relay
cd my-claude-relay
git remote set-url origin https://github.com/YOUR_NAME/my-claude-relay.git
git push -u origin main

Repeat the clone (from your private repo) on the second machine.

2. Run the setup script

npm run setup

The script will ask:

  • Your workspace path (press Enter to use the current directory)
  • A name for your first machine (e.g. home, laptop)
  • A name for your second machine (e.g. office, desktop)
  • Each machine's hostname (run hostname on it; press Enter to use this machine's, or fill in later)

It will:

  • Update CLAUDE.md with your machine names and hostnames
  • Update relay/last-context.md with your machine names
  • Print the exact JSON block to add to your settings file (copy-paste ready)

3. Add hooks to your Claude Code settings

Your settings file location:

OS Path
Windows C:\Users\YOUR_NAME\.claude\settings.json
macOS / Linux ~/.claude/settings.json

Open the file and add the PreCompact, PostToolUse, and Stop entries printed by the setup script. If "hooks" already exists, merge the new keys into it.

Restart Claude Code after saving.

4. Configure notifications (optional)

Only needed if you want push notifications. Supports Telegram, Slack, Discord, ntfy.sh.

node scripts/telegram/setup.js

The wizard asks which service you want, collects your credentials, and registers them as GitHub Secrets automatically. Takes about 2 minutes.

After setup, send a notification from anywhere (local session, Routines, PC off):

node scripts/telegram/notify-telegram.js "your message"
# Delivered via GitHub Actions in ~1 minute

Without setup, the hook silently exits — nothing breaks.

5. Verify

npm run verify

Expected output: all checks passed (Node.js version, settings.json hooks, relay file).

For individual component tests:

npm run test:pre-compact   # should print the rules block
npm run test:telegram-hook # should exit silently (no flag file = no send)
npm run test:stop-hook     # should exit silently (relay not modified = no write)

Restart Claude Code and open a new session. If the hooks are registered correctly, you will see no errors and sessions will work normally.


How It Works Day-to-Day

First session of the day:

  1. git pull --rebase --autostash — get every other node's notes (pull-first)
  2. Read relay/last-context.md — lines tagged to you + shared tasks
  3. Delete the lines tagged to you after processing (ownership rule)
  4. Work on incomplete tasks

End of session:

  1. Write a tagged line (e.g. [→node-b]) with a summary in relay/last-context.md
  2. Run scripts/sync.sh (or scripts/sync.ps1) — pulls first, then commits and pushes. Never bare-push: it would drop whatever another node pushed while you worked.

Same day, second session: read relay/last-context.md only. No pull needed.


Maintenance and Version Compatibility

What never breaks

  • relay/last-context.md — plain markdown, no dependencies
  • CLAUDE.md — plain text, no dependencies
  • The handoff protocol itself

These work regardless of Claude Code version updates.

What may need updating

Component Risk How to fix
Hook registration format (settings.json) Low — format is stable Update key names if Claude Code changes them
PreCompact hook event name Low Update event name in settings.json
context-hook.js Telegram API call Very low — Telegram API is stable Update endpoint if Telegram changes it

If a Claude Code update breaks something:

  1. Check Claude Code release notes for hook changes
  2. Open an issue — someone in the community likely hit the same problem
  3. The fix is almost always a one-line change in settings.json

Can users maintain this themselves?

Yes. The hooks are under 100 lines each, with no complex logic. Any Claude Code user who can edit JSON can fix a hook registration.

For the target setup (two or three machines, one Claude session writing to the relay at a time), the relay protocol itself needs no maintenance — it's plain markdown with a fixed set of sections. That stops being true once you scale it up: running this at a higher node count with many automated processes writing to the relay frequently, we eventually hit file bloat, stale entries nobody cleaned up, and long-running notes that never got acknowledged. Fixing that took several small housekeeping scripts (staleness checks, forgetting-decay for old acknowledged notes, folding long entries down to a pointer) that aren't part of this project — they were specific to that heavier deployment. If your usage grows past casual two-machine handoffs, budget for writing the equivalent yourself.


Troubleshooting

Hooks not running:

  • Confirm you saved ~/.claude/settings.json and restarted Claude Code
  • Run node scripts/hooks/pre-compact.js manually — if it errors, fix the Node.js path
  • Check that paths in settings.json use the correct separator for your OS

Windows path errors:

  • Paths in JSON strings inside settings.json need 4 backslashes: C:\\\\Users\\\\...
  • The setup script generates the correct format automatically

Notifications not arriving:

  • Run node scripts/telegram/setup.js to confirm the service is configured
  • Check GitHub Actions tab in your repo for workflow run status
  • Test manually: node scripts/telegram/notify-telegram.js "test" — should print "Queued"
  • If GitHub Actions fails: verify NOTIFY_SERVICE and matching secrets are set (gh secret list)

Merge conflict in relay/last-context.md:

  • Keep the version with more content
  • Never drop another node's tagged lines
  • Merge every node's lines back in manually, then commit

git pull fails on session start:

  • Check network and git credentials
  • The relay still works offline — just skip the pull and sync when back online

File Structure

claude-toudou/
├── CLAUDE.md                         # Session rules, relay protocol, channel routing
├── .claudeignore                     # Keeps large files out of Claude's context
├── relay/
│   └── last-context.md               # The AI-to-AI handoff file
├── scripts/
│   ├── sync.sh                       # Pull-first sync (Linux/macOS); the hub runs this on cron
│   ├── sync.ps1                      # Pull-first sync (Windows/PowerShell)
│   ├── setup.js                      # Interactive setup helper
│   ├── verify.js                     # Installation checker (npm run verify)
│   ├── hooks/
│   │   ├── pre-compact.js            # PreCompact hook: cumulative compaction
│   │   └── stop-hook.js              # Stop hook: session end relay reminder
│   └── telegram/
│       ├── context-hook.js           # PostToolUse hook: compaction notifier
│       ├── notify-telegram.js        # GitHub Actions sender (works when PC is off)
│       ├── setup.js                  # First-run wizard: Telegram/Slack/Discord/ntfy
│       ├── send-telegram.js          # Standalone direct sender (Node.js)
│       ├── send-telegram.py          # Standalone direct sender (Python fallback)
│       └── .env.example
├── .github/
│   └── workflows/
│       └── send-telegram.yml         # GitHub Actions: receive pending file → send → cleanup
├── .claude/
│   └── settings.template.json        # Reference for hook configuration
└── docs/
    ├── relay-protocol.md             # How the AI-to-AI handoff works
    └── telegram-isolation.md         # Why the flag pattern exists

Design Principles

  • AI-to-AI by design — the relay file is written to be understood and acted on by Claude
  • Pull before push, always — the rule that lets nodes run concurrently without forking
  • Concurrency over turn-taking — safety from ownership + guards, not from forbidding overlap
  • An optional always-on hub — keeps every node current on a schedule, no keyboard required
  • No services beyond git hosting — the core relay needs only git and Node.js; the optional notification path uses GitHub Actions on the repo you already have
  • Silence is the default — notifications only happen when Claude explicitly calls notify-telegram.js
  • Works from any environment — local sessions, Web Routines, or when PC is off (via GitHub Actions)
  • Compaction is cumulative — context deepens across compressions, not shallows
  • Maintenance-free protocol — only hooks need occasional updates, not the core system

Built and first operated by Toudou (糖豆) — an AI agent named after a cat who lived for ten years.

About

Persistent memory and session continuity for Claude Code across multiple machines — git-based AI-to-AI handoff, concurrent nodes, optional always-on hub

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages