Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Repository files navigation

hearth

Carry your dev hearth between machines.

hearth is a cross-platform CLI that keeps the configuration of your developer tools in sync across every machine you use — Mac, Linux, Windows — through a private git repo that you own. No sync server, no third-party cloud, no telemetry. Just you, your machines, and GitHub.

It was built because setting up a new laptop — restoring your Claude Code agents, your VSCode settings, your shell aliases, your Gemini CLI config, your git preferences — is a day of friction that nobody should have to do twice.

Project status: Phase 1 (local CLI loop works for Claude Code; additional profiles, 3-way merges, automatic scheduling, and the VSCode extension are on the roadmap — see Roadmap below).


Table of contents


Why hearth

If you use modern developer tools (Claude Code, VSCode, Gemini CLI, a customized shell, etc.), your personal setup is now a meaningful artifact:

  • Custom Claude Code subagents you've hand-crafted over weeks.
  • Skills, memories, commands in ~/.claude/.
  • VSCode settings, keybindings, snippets tuned to your workflow.
  • A shell RC full of aliases and functions.
  • Git aliases, gh CLI config, tool-specific preferences.

Today all of this lives in one place: the laptop in front of you. When you get a new machine, wipe a drive, or switch between work and home, you lose it — or you spend hours manually reassembling it, guessing at what's missing.

Existing solutions don't fit:

  • Dotfile managers (chezmoi, yadm, rcm) are great for shell rc files but assume your full home directory is version-controlled. They don't handle secrets scrubbing, don't understand JSON structural merges, don't re-inject API keys from a keychain, and have no story for tools like Claude Code whose config includes machine-generated artifacts.
  • VSCode Settings Sync is VSCode-only.
  • Cloud-based config sync tools require you to trust a vendor with the contents of your .zshrc.

hearth is a single, opinionated tool that covers the whole surface: AI CLI tools, editor, shell, git — via a git repo that you own and can delete at any time.


What it does

Out of the box, hearth is aware of these tools and knows the right files to sync for each:

Tool What gets synced What stays local
Claude Code CLAUDE.md, agents/, skills/, team-memory/, commands/, installed-plugins list, settings.json (scrubbed) .credentials.json, session data, cache, project history, telemetry
VSCode (Phase 3) settings.json, keybindings.json (per-host), snippets/, installed-extension list Extension binaries (reinstalled from the list), per-workspace state
Gemini CLI (Phase 3) Config directory Cached auth tokens
Shell (Phase 3) .zshrc / .bashrc — shared core + per-host fragment Secret-bearing aliases, private env-var blocks
Git (Phase 3) Aliases and shared [core] config Per-host user.email, signing keys
GitHub CLI (Phase 3) ~/.config/gh/config.yml Auth tokens

You can extend this: every synced file is declared in a manifest.yaml inside your data repo. Adding a new tool is a matter of editing that file.


What it explicitly does NOT do

hearth will never sync:

  • SSH private keys (~/.ssh/id_*). If your data repo is ever exposed, you don't want your SSH keys in it. Regenerate per machine.
  • GPG keys (~/.gnupg/). Same reason.
  • Claude's .credentials.json. Re-run claude login on a new machine.
  • .env, .env.local. Secrets in files live with the project.
  • *.pem, *.p12, *.pfx, *.der and any path containing private/. Hard-coded never-sync list.
  • API keys inside config files. Declared secrets are scrubbed at push, replaced with <<HEARTH:…>> placeholders, and re-injected on apply from your OS keychain. They never enter git history.

This list is hard-coded in the tool and cannot be overridden by the user's manifest. Even if you try, hearth will block it.


How it works

  ┌────────────┐      push (scrubbed)      ┌────────────────────┐
  │ Your local │ ────────────────────────▶ │ Your private git   │
  │  configs   │                           │ repo on GitHub     │
  │            │ ◀──────────────────────── │ (ONLY you have     │
  └────────────┘      pull + apply          │  access)           │
        │           (re-inject secrets)    └────────────────────┘
        │                                            ▲
  OS keychain                                        │
  (secrets vault)                                    │ pull + apply
                                             ┌──────┴──────┐
                                             │ Another     │
                                             │ machine     │
                                             └─────────────┘
  1. You keep your configs on each machine as normal.
  2. hearth sync reads them, scrubs declared secrets, writes them into a local clone of your private data repo, and pushes.
  3. On another machine, hearth sync pulls, writes the configs atomically to disk, and re-injects your secrets from that machine's keychain.
  4. GitHub is just a durable filesystem and an audit log — it has no idea what hearth is.

There is no hearth server. The only external service involved is git talking to your private repo.


Install

hearth requires Node.js 20 or newer. Check with node --version.

Prerequisites (all platforms)

  1. Node.js 20+nodejs.org or nvm / fnm.
  2. git — comes preinstalled on most systems.
  3. GitHub account with permission to create a private repo.
  4. (Recommended) GitHub CLI (gh) — makes auth and repo creation one command. cli.github.com.

macOS

# via Homebrew (recommended)
brew install node git
brew install gh          # optional but recommended

# install hearth — published to npm once v0.1.0 releases
npm install -g hearth

# Today (building from source)
git clone https://github.com/yetesfa/hearth ~/Documents/hearth
cd ~/Documents/hearth
npm install && npm run build && npm link

After npm link, the hearth binary is on your PATH.

If npm link complains about permissions, see Troubleshooting.

Linux

# Debian/Ubuntu
sudo apt install -y nodejs npm git
# or, for an up-to-date Node
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs

# Fedora/RHEL
sudo dnf install -y nodejs git

# Arch
sudo pacman -S nodejs npm git

# GitHub CLI (optional)
# Follow https://cli.github.com/manual/installation

# install hearth
npm install -g hearth           # once published
# or, from source:
git clone https://github.com/yetesfa/hearth ~/Documents/hearth
cd ~/Documents/hearth
npm install && npm run build && npm link

Linux-only note: for the automatic scheduler (Phase 4 — hearth install) to run when you're logged out, hearth will run loginctl enable-linger $USER. This requires one-time sudo access and is opt-in.

Windows

Windows supports are in two flavors:

Option A — Native PowerShell (recommended for most users):

# Install Node.js 20+ from https://nodejs.org or:
winget install OpenJS.NodeJS.LTS
winget install Git.Git
winget install GitHub.cli   # optional

# install hearth
npm install -g hearth
# or from source:
git clone https://github.com/yetesfa/hearth $HOME\Documents\hearth
cd $HOME\Documents\hearth
npm install; npm run build; npm link

Option B — WSL (if you live in a Linux shell on Windows): follow the Linux instructions inside your WSL distro. hearth will then sync the Linux side of your machine, not the Windows side — choose one or the other depending on where your configs actually live.

Windows-only notes:

  • Paths use %APPDATA%\Code\User\ for VSCode instead of ~/.config/Code/User/hearth handles this translation automatically.
  • The scheduler uses Windows Task Scheduler at user-level (no admin elevation). Registered at logon.

First-time setup

Two different flows depending on whether this is the first machine you're setting hearth up on, or you're adding another machine to an existing setup.

Flow A — brand-new user

This is for your first machine with hearth.

# Authenticate to GitHub once (if you installed gh)
gh auth login

# Run the guided wizard
hearth init

The wizard will:

  1. Briefly explain what hearth does and what it won't sync.
  2. Offer to create a private data repo for you (via gh repo create) — pick a name like personal-configs. You can also point at an existing empty private repo you already made.
  3. Detect which tools are installed on this machine and let you opt-in per profile.
  4. Write a manifest.yaml into the data repo describing what will be synced.
  5. Show a dry-run: every file that would be pushed, with any secret redactions preview.
  6. On your confirmation, do the real first push.
  7. Offer to register the automatic scheduler (Phase 4).

After this, your data repo contains your current configs (scrubbed) and you're ready to set up your second machine.

Note: in the current Phase-1 build the interactive wizard is a stub. For now, pass --from <url> (see Flow B) with a repo you created on GitHub.

Flow B — new machine, existing data repo

This is for every machine after the first.

# Authenticate first
gh auth login
# or provide a GitHub PAT when hearth asks

# Clone the existing data repo into hearth's workspace
hearth init --from [email protected]:<you>/<your-data-repo>.git

# Preview what would be written to disk, then apply for real
hearth apply --dry-run
hearth apply

hearth will write your Claude Code agents, VSCode settings, etc. into the expected OS-specific paths (~/.config/Code/User/ on Linux, ~/Library/Application Support/Code/User/ on Mac, %APPDATA%\Code\User\ on Windows).

Then finish the per-machine manual steps that hearth prints:

Finish setup manually:
  • Run `claude login` to reauth Claude Code
  • Run `gh auth login` if not already done
  • Generate a fresh SSH key: ssh-keygen -t ed25519
  • Install VSCode extensions: hearth apply-extensions  (Phase 3)
  • Register scheduler: hearth install                  (Phase 4)

These are deliberately not synced. Syncing SSH private keys would turn your data repo into a single point of compromise forever, and reauthenticating Claude takes about thirty seconds.


Daily use

Once set up, the loop is simple.

# Most of the time, do nothing — Phase 4 watcher + scheduler handles sync automatically.

# Before a long trip / before switching machines, manually force a sync:
hearth sync

# After returning to a machine you haven't used in a while:
hearth sync

# Preview what would happen before doing it:
hearth sync --dry-run

# See the current state
hearth status

# See the last 20 audit entries
hearth log    # (Phase 4)

The single most important command is hearth sync. It pulls from the remote, pushes your local changes, and writes applicable remote updates to disk — all as one atomic operation.


Configuration

The manifest

The contents of your data repo are governed by a single file — manifest.yaml at the repo root. It looks like this:

version: 1
entries:
  - source: "~/.claude/CLAUDE.md"
    repo: "shared/claude/CLAUDE.md"
    scope: shared
    merge: text3way

  - source: "~/.claude/agents/"
    repo: "shared/claude/agents/"
    scope: shared
    merge: text3way
    recursive: true

  - source: "~/.claude/settings.json"
    repo: "shared/claude/settings.json"
    scope: shared
    merge: json3way
    scrub:
      - jsonPath: "$.env.ANTHROPIC_API_KEY"
      - jsonPath: "$.env.OPENAI_API_KEY"

  - source: "~/.config/Code/User/keybindings.json"
    repo: "hosts/{host}/vscode/keybindings.json"
    scope: host
    merge: json3way

Each entry has:

  • source — the file or directory on your machine. Use ~/ for home. OS-specific paths are handled automatically for well-known tools.
  • repo — where in the data repo this lives. {host} is replaced with your hostname when scope: host.
  • scopeshared (same content on every machine), host (per-machine, never conflicts), or template (generated from shared + host fragments; good for .zshrc).
  • mergetext3way, json3way, setunion (for extension lists), or lww (last-writer-wins). Phase 2 implements the merge strategies; Phase 1 is fast-forward only.
  • scrub — optional list of secret-redaction rules. Supports JSON-path ($.env.KEY) and regex.
  • recursive — for directories, include all files under it.

Edit manifest.yaml in the data repo, commit, push — all other machines pick up the change on their next sync.

Per-machine vs shared files

hearth distinguishes three situations:

Scope Example How it behaves
Shared ~/.claude/CLAUDE.md, custom agents One canonical copy in the repo. Edits on any machine propagate to all.
Host VSCode keybindings.json (keys differ on Mac vs PC), user.email in .gitconfig Each machine has its own copy under hosts/<hostname>/. Can never conflict with another machine.
Template .zshrc (mostly shared, with machine-specific bits) The real file is assembled from a shared fragment + per-host fragment. Phase 3 feature.

If you're not sure which scope to use, start with shared. When a file starts diverging between machines, promote it to host.

Scheduling (planned)

Planned for Phase 4. Once hearth install is implemented, it will register the following on each OS:

OS Mechanism What runs
macOS launchd LaunchAgents (~/Library/LaunchAgents/com.hearth.*.plist) A watcher process (KeepAlive=true) and a scheduled sync (StartCalendarInterval, every 6h).
Linux systemd user units (`~/.config/systemd/user/hearth-*.service .timer) + loginctl enable-linger`
Windows Task Scheduler (user-level, no admin) Watcher registered at logon, restart-on-fail. Sync task every 6h, "run ASAP if missed".

You'll be able to adjust or disable either layer. Until Phase 4 ships, run hearth sync manually (or wire it into your own cron / launchd / Task Scheduler).


Security model

Short version:

  • Your data repo must be private. hearth init will check and refuse to point at a public repo.
  • Secrets never enter git. Declared secrets (per scrub rules in the manifest) are replaced with <<HEARTH:…>> placeholders before any commit.
  • A safety-net leak scan runs on every push. If any of ~10 common secret patterns (Anthropic keys, OpenAI, GitHub PATs, AWS keys, Stripe keys, JWTs, etc.) survive scrubbing, the push aborts — no git commit is created.
  • Secrets live in your OS keychain. When hearth apply writes configs to disk, it pulls the real values from Keychain Access (Mac) / Secret Service / GNOME Keyring (Linux) / Credential Manager (Windows) and injects them into the file.
  • Hard-coded never-sync list. Regardless of what your manifest says, paths matching .credentials.json, id_* (SSH keys), *.pem, .env*, etc., are silently dropped from every snapshot.
  • No telemetry. hearth phones home to nobody.

The threat model and full list of scrubbed patterns will live in SECURITY.md (written during Phase 5.5, OSS launch).

What this does not protect against:

  • A compromised GitHub account. If someone steals your GitHub credentials they can read the repo. Use 2FA.
  • A compromised machine. If someone has root on your laptop, they can read your keychain too.
  • A user who manually commits a secret into the data repo bypassing hearth. Don't do that — the scrubber only runs when hearth creates the commit.

Command reference

Command What it does Status
hearth init First-time setup wizard: choose / create data repo, detect profiles, generate manifest. Phase 5 (today: pass --from <url>).
hearth init --from <url> Clone an existing data repo into the workspace. Working.
hearth sync [--dry-run] Pull → merge → push → apply. The normal daily command. Working (fast-forward only).
hearth apply [--dry-run] Write workspace state to local filesystem. Does not touch the remote. Working.
hearth push Local → workspace → remote only. Phase 2.
hearth pull Remote → workspace only. Phase 2.
hearth status Show last sync, workspace state, pending changes. Working.
hearth doctor Verify auth, scheduler, watcher, keychain, lingering. Phase 4.
hearth install Register OS scheduler + file watcher. Phase 4.
hearth uninstall Remove scheduler + watcher, keep data. Phase 4.
hearth rollback --to <ts> Restore a pre-apply backup. Phase 5.
hearth log Tail the audit log. Phase 4.
hearth secret set <account> <value> Store a secret in the OS keychain. Phase 2.
hearth secret get <account> Print a secret (in a TTY, with confirmation). Phase 2.
hearth secret list List keychain entry names (values never shown in bulk). Phase 2.

Run hearth --help or hearth <command> --help for flag details.


Troubleshooting

npm link fails with EACCES on macOS/Linux

npm's global prefix is owned by root. Either fix the prefix or use a version manager:

# Option 1 — move npm's global prefix under your home
mkdir -p ~/.npm-global
npm config set prefix ~/.npm-global
# add to your shell rc:
export PATH="$HOME/.npm-global/bin:$PATH"

# Option 2 — use fnm / nvm so npm lives under your home automatically

keytar native build fails

keytar talks to the OS keychain via a native module. On Linux it needs libsecret:

# Debian/Ubuntu
sudo apt install libsecret-1-dev

# Fedora
sudo dnf install libsecret-devel

# Arch
sudo pacman -S libsecret

Then npm rebuild keytar. On macOS and Windows, keytar uses the OS keychain directly — no extra install needed.

hearth sync says "diverged"

In Phase 1, hearth only handles fast-forward pulls and pushes. If both your remote and your local machine have changes, pick a side:

# Prefer local (discard remote changes since last sync)
hearth push   # Phase 2

# Prefer remote (discard local changes)
hearth pull && hearth apply   # Phase 2

Until Phase 2 ships, resolve manually inside ~/.hearth/repo using plain git, then push.

"secret leak detected" — push aborted

The safety-net scanner found a secret-looking pattern in content you're about to push. Two fixes:

  1. Add a scrub rule for the file in manifest.yaml:
    - source: "~/.somefile.json"
      repo: "shared/somefile.json"
      scope: shared
      merge: json3way
      scrub:
        - jsonPath: "$.secretKey"
  2. Remove the secret from the source and put it in an environment variable or the keychain instead.

Once scrubbing is in place, hearth sync --dry-run will show the redacted output before you push for real.

A secret already leaked into my data repo

GitHub repo history is permanent even after deletion. The safest recovery:

  1. Rotate the leaked credential immediately (revoke the API key, regenerate the token).
  2. Delete the data repo entirely and create a new one.
  3. Run hearth init --from <new-url> --force on each machine.

Future hearth versions will add a hearth rotate-repo command to automate steps 2 and 3.


FAQ

Why a git repo and not a sync server? Because git is already a perfectly good sync protocol, GitHub is a credibly durable store, and adding a server is one more piece to secure, pay for, and maintain. hearth sticks to the "private plumbing, no bespoke infrastructure" principle.

Can I use a GitLab / Bitbucket / self-hosted git? Yes — pass any URL that git can clone to hearth init --from. The gh-based convenience flows won't work, but manual setup does.

What if I don't want to sync everything on the default list? Edit your data repo's manifest.yaml. Remove entries you don't want, add entries for tools we don't support yet. On the next sync, your changes take effect.

Can multiple people share one hearth repo (team / family)? Not recommended. hearth is designed for one person with multiple machines. For team defaults, put shared conventions in a chezmoi-style base and layer hearth on top for personal preferences.

Will hearth ever support encryption-at-rest? Phase 7. Using age for files marked encrypted: true in the manifest, with the key in your OS keychain. Useful for configs that can't be fully scrubbed (for example, private MCP server URLs or Gemini project IDs).

Can I extend hearth to sync my own tool? Yes — add an entry to manifest.yaml. For built-in detection / auto-add via hearth init, contribute a profile under src/profiles/. Each profile is ~30 lines; see src/profiles/claude-code.ts as a reference.

Does this work offline? Local commits happen offline. Push/pull need network. hearth apply (materialize workspace → disk) is fully offline.

I'm not a developer. Should I use this? Probably not — hearth assumes you're comfortable with the CLI, git, and a text editor. If those aren't routine, chezmoi or a setup script are simpler starts.


Roadmap

  • Phase 1 — CLI scaffold, Claude Code profile, fast-forward sync, scrubbing, vault, atomic writes, backups.
  • Phase 2 — 3-way JSON merge, git 3-way text merge, set-union for extension lists, secret keychain CLI commands.
  • Phase 3 — VSCode, Gemini, shell (template+fragments), git, GitHub CLI profiles.
  • Phase 4 — Watcher daemon + OS scheduler (systemd / launchd / Task Scheduler), install / uninstall / doctor.
  • Phase 5 — Cross-OS installers, guided init wizard with gh repo create, rollback, log tailer.
  • Phase 5.5 — OSS launch: SECURITY.md, CONTRIBUTING.md, CI matrix, release automation, npm publish, hearth-starter template.
  • Phase 6 — VSCode extension with 3-way merge editor integration.
  • Phase 7 — Encryption-at-rest via age.

Contributing

Contributions are very welcome — especially new profiles for tools we don't yet cover (Neovim, tmux, Starship, Zed, JetBrains IDEs, etc.). Each profile is a single TypeScript file under src/profiles/ — see src/profiles/claude-code.ts as the canonical example.

Before committing:

npm run typecheck
npm run test           # tests land in Phase 2

Detailed contributor docs land in CONTRIBUTING.md during Phase 5.5.


License

MIT. See LICENSE.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages