A boilerplate for running Claude Code as an "always-on" assistant across two machines, using a shared GitHub repo as the sync layer. Companion to thetechedit.com/articles/always-on-claude-code.
Heads up: this is not a zero-maintenance setup. Expect occasional tinkering, particularly when Windows updates, when Claude Code itself ships changes, or when you tweak your scheduled tasks. The article covers the trade-offs honestly.
Tip: the easiest way to set this up is to ask Claude Code itself to help. Open a session in your working directory, point Claude at this repo (clone or fetch it), and ask it to walk you through the setup. The steps below are written for humans, but Claude can read the README, scripts, and
CLAUDE.mdtemplate and help you customise as you go - including merging the right bits into your existing globalCLAUDE.md.
- Scheduled jobs that run when your computer is off. Daily memory consolidation, periodic checks, anything you'd otherwise forget to run.
- Remote sessions from your phone. Connect to a live Claude Code session on the always-on machine via the mobile app - fire off a task on the train, have results waiting when you arrive.
- Memory and context that follow the work, not the device. Both machines share the same
~/.claudefolder via a directory junction; the sync script keeps GitHub in step. No "wait, which machine did I do that on?".
Two machines run the same Windows 11 setup. Your laptop is the daily driver; the always-on machine (a cheap Mini PC, in my case) handles scheduled work and stays available for remote sessions while the laptop is off. Neither machine talks to the other directly - GitHub is the sync layer. Discord receives webhook alerts when something fails.
The full architecture, motivation, and trade-offs are covered in the companion article.
| Path | Purpose |
|---|---|
README.md |
This guide. |
CLAUDE.md |
Merge-style template for your global Claude Code instructions. |
LICENSE |
MIT. |
settings.example.json |
Template for settings.json (which holds your Discord webhook URL). |
scripts/claude-sync.ps1 |
Pulls, pushes, writes health status, alerts on failure, and clones/pulls nested repos. |
scripts/claude-heartbeat.ps1 |
Keeps the Claude Code OAuth token fresh so remote sessions don't drop. |
scripts/setup-junction.ps1 |
One-time helper: creates the ~/.claude → repo junction. |
scripts/project-repos.txt |
List of nested project repos for the sync script to clone or pull alongside the main repo. |
tasks/*.xml |
Importable Windows Task Scheduler entries for sync, heartbeat, and one example. |
health/status.json |
Last-sync status; updated every successful sync. |
examples/ |
Illustrative scheduled jobs you can copy and adapt. |
- Two Windows 11 machines. A daily driver and an always-on machine. Same OS on both ends keeps the setup steps and paths identical.
- Git and Node.js on both machines.
- Claude Code installed via npm:
npm install -g @anthropic-ai/claude-code. - A Discord channel you control, for failure alerts via webhook.
- A GitHub repo to act as the sync bus. Private is fine.
Choose a path and clone to the same path on both machines. This matters - paths leak into Claude's memory and handoff files, and matching paths means the same notes work on both ends.
git clone https://github.com/yourusername/your-repo.git "C:\Users\<you>\Claude Code"Claude Code reads its config from ~/.claude (which on Windows resolves to C:\Users\<you>\.claude). To share state between both machines, we point that path at this repo using a Windows directory junction.
On both machines:
cd "C:\Users\<you>\Claude Code"
.\scripts\setup-junction.ps1The script is idempotent - re-running is safe. It checks whether a junction already exists and refuses to overwrite a real folder.
The junction's source and target must be on the same drive.
Open CLAUDE.md in this repo and integrate its sections into your global ~/.claude/CLAUDE.md. Each section has a merge comment above it telling you whether it's a new section to add, an existing one to merge with, or a rule to replace. If you don't have a CLAUDE.md yet, you can use this file directly as a starting point.
The sync script reads DISCORD_WEBHOOK_URL from settings.json at the repo root. To set it up:
-
In your Discord server, go to Server Settings → Integrations → Webhooks, create a new webhook for the channel you want alerts in, and copy the URL.
-
Copy the example file:
Copy-Item settings.example.json settings.json -
Open
settings.jsonand paste your webhook URL intoenv.DISCORD_WEBHOOK_URL.
settings.json is in .gitignore, so your webhook URL won't be committed.
The tasks/ folder contains three XMLs to import into Windows Task Scheduler on the always-on machine:
claude-sync.xml- runs the sync script six times a day plus 60 seconds after bootclaude-heartbeat.xml- keeps the OAuth token fresh (twice daily)example-imax-check.xml- a sample daily check, useful as a smoke test
For each XML:
- Open the file in a text editor and replace
C:\Users\YOU\Claude Codewith your actual repo path. - In Task Scheduler: Action → Import Task... and select the file.
- Change the User or Group in the import dialog to your active Windows account so the task has permission to run Git and PowerShell.
If you have separate Git repos inside the main folder, Git stops tracking their contents (which breaks the sync). To keep them in step:
-
Add their folder names to your main repo's
.gitignore. -
Add a line per repo to
scripts/project-repos.txt:https://github.com/yourusername/your-repo.git relative/path/to/folder
The sync script reads this file on each run and clones or pulls each nested repo alongside the main one.
After the first sync runs (manually trigger it from Task Scheduler if you don't want to wait), check the health file from your laptop:
git pull; Get-Content health/status.jsonYou should see something like:
{
"last_sync": "2026-05-07T07:00:12+00:00",
"status": "OK",
"hostname": "your-mini-pc"
}If the timestamp is more than eight hours old, or status is FAILED, check Discord for the error message - the sync script posts there on failure.
For a heavier smoke test, set up the IMAX example task (tasks/example-imax-check.xml together with examples/imax-ticket-check/) - it runs daily, posts to Discord on success or failure, and is straightforward to debug if anything's wrong.
In any Claude Code session on the always-on machine, run:
/remote-control
This opens the session for connection from the iOS or Android Claude Code app. Open the app, connect to the session, and fire off tasks from your phone.
Caveat: if you
/clearthe session from the app, the remote connection drops. To reconnect you'll need to run/remote-controlfrom the always-on machine again.
Two patterns:
- Webhook alerts (one-way) - already covered above. The sync script posts on failure.
- Interactive sessions - if you set up a Discord MCP server connected to a live Claude Code session, you can DM a Discord bot and Claude responds in the same thread. The Discord bot needs an active Claude Code session at all times - if the session goes idle, the bot stops responding until you re-engage. Setup for the MCP server is out of scope for this repo.
Default Claude Code memory lives in ~/.claude/memory/. Because ~/.claude is a junction to this repo, that folder is automatically shared between both machines, and the sync script commits any memory writes back to GitHub on each run.
This boilerplate also ships a starter handoff.md at the repo root. The CLAUDE.md template tells Claude to read it at session start and rewrite it at session close. It has two sections (Last Worked On and Open Threads / Next Actions), kept under 80 lines, and gives the next session a quick orientation. The sync script commits updates like everything else, so both machines see the latest state.
If you want richer per-session episode notes and a consolidation pipeline that promotes them into long-term semantic memory, see the article's "What runs while my laptop is closed" section. The implementation is opinionated and bespoke, so it isn't shipped here as part of the boilerplate.
- Don't run the same project on both machines at the same time. Memory writes will conflict and handoff files will overwrite each other. Treat the always-on machine as scheduled-only; do interactive work on the laptop.
/clearends a remote-control connection. You can/clearfrom the mobile app, but you'll need physical access to the always-on machine to reconnect.- Reboots end any active remote session. Scheduled tasks pick back up automatically; remote sessions don't. Set Windows Active Hours on the always-on machine to avoid update reboots during likely-active times.
- Interactive Claude Code commands stay at the terminal.
/mcp,/plugin,/resumeetc. open menus that don't render over remote-control. - The Discord MCP bot needs an active Claude Code session. If the session times out, the channel goes dark with no signal. Pair it with the heartbeat to keep things alive.
- Nested project repos break sync silently. If you have a Git repo inside the main folder without
.gitignore+project-repos.txtentries, the always-on machine won't know about updates.
- The companion article: Always-On Claude Code on thetechedit.com - the full motivation, trade-offs, and "is it for you?" framing.
examples/- illustrative scheduled tasks you can copy and adapt for your own use cases.
MIT - see LICENSE.
