Recif lets you keep one master ~/.claude directory and spin up lightweight,
isolated profiles (~/.claude-enzyme, ~/.claude-personal, …) that share
the master's config via symlinks but authenticate as separate Claude accounts.
It decouples account identity (config-directory path → macOS Keychain slot)
from config data (symlinks into the master), so history, sessions, settings,
hooks, and plugins are shared across every profile while each profile logs in as
its own subscription. See PRD.md for the full design.
Claude Code derives its Keychain credential slot from a hash of the
CLAUDE_CONFIG_DIR path string. A real directory whose contents are
symlinks into the master therefore gets its own credential slot while sharing
all state. Recif automates creating and maintaining those profile directories.
- Every top-level master entry is symlinked into each profile, except the
denylist (
daemon/,.credentials.json,*.lock,*.db*/*.sqlite*,statsig/,.git*). daemon/is always a real per-profile directory (never symlinked).- A background daemon (via
launchd) keeps every profile in sync with the master as files come and go. - Profiles refuse to launch when the sync daemon is unhealthy (the launch gate), so you never land in an out-of-sync session unknowingly.
cargo build --release
install -m 755 target/release/recif ~/.local/bin/recif # a dir on your PATH
codesign --force --sign - ~/.local/bin/recif # macOS: re-sign after copymacOS codesign gotcha.
cargoad-hoc-signs the binary at its build location. Plaincp/installto another path invalidates that signature and, under the hardened runtime, macOS kills the copy on exec withKilled: 9(SIGKILL, exit 137) — including the launchd daemon, which would then crash-loop. Re-sign the installed copy withcodesign --force --sign -. Install to a stable location (not thetarget/dir): the daemon plist records the binary's absolute path, so acargo cleanor moved repo would otherwise break the daemon. Re-runrecif doctorafter moving the binary to regenerate the plist.
recif add <name> [--master ~/.claude] [--alias] [--description <s>] [--rc <path>]
recif remove <name> [--keep-daemon] [--yes]
recif list
recif doctor- add — creates
~/.claude-<name>, links the master, creates a realdaemon/, records the profile in~/.recif/config.toml, installs+starts the daemon, and (with--alias) addsalias claude-<name>="recif launch <name>"to your shell rc. Idempotent. - remove — safely unlinks each symlink (never following it into the master),
removes the real
daemon/(unless--keep-daemon), and drops the config entry and alias. The master and Keychain are untouched. Prompts for confirmation (--yesto skip). - list — shows each profile's health, sync status, alias presence, and whether a Keychain slot exists, plus a daemon health line.
- doctor — checks the whole setup and auto-fixes what it can (reload the
daemon, repair symlinks, recreate
daemon/, remove leaked files). Missing Keychain slots are reported, never created (run/loginonce per profile).
The alias routes through the launch gate:
claude-enzyme # = recif launch enzyme
claude-enzyme --resume # args pass straight through to claudeWhen the daemon is healthy this execs claude instantly. When it's down you
get a one-keystroke prompt to run recif doctor; declining aborts without
launching.
Each profile has its own Keychain slot. Run the profile once and /login:
claude-enzyme # then /login with that accountIf you already have a full-copy ~/.claude-enzyme, convert it in place:
recif add enzymeFiles present in ~/.claude-enzyme but not in the master are moved up to the
master and replaced with symlinks; files present in both let the master win.
~/.recif/config.toml (canonical absolute paths throughout):
version = 1
master = "/Users/you/.claude"
[daemon]
launchd_plist = "/Users/you/Library/LaunchAgents/com.recif.daemon.plist"
log_file = "/Users/you/.recif/daemon.log"
[[profiles]]
name = "enzyme"
description = "Enzyme work account"
created_at = "2026-07-07T00:00:00Z"
path = "/Users/you/.claude-enzyme"recif uninstall # stops+removes the daemon, aliases, profiles, ~/.recif
recif uninstall --keep-profiles # same, but leave the profile dirs on diskuninstall stops and unloads the launchd daemon, deletes its plist, removes
Recif-managed shell aliases, safely removes each profile directory (unlink only
— never following symlinks into the master), and deletes ~/.recif. It never
touches the master ~/.claude or Keychain credentials. It's idempotent and
best-effort: even a partially-installed setup can be cleaned. Finally, remove
the binary itself (rm ~/.local/bin/recif).
If you need to do it by hand (e.g. the binary is gone):
launchctl unload ~/Library/LaunchAgents/com.recif.daemon.plist
rm ~/Library/LaunchAgents/com.recif.daemon.plist
# remove the recif-managed alias lines (marked "# recif-managed") from ~/.zshrc or ~/.bashrc
rm -rf ~/.recif⚠ Never
rm -rfa profile directory by hand — a naive recursive delete follows the symlinks into the master and destroys shared data. Userecif remove <name>(orrecif uninstall), which unlink the links only.
cargo test --features testutil # unit + integration tests
RECIF_LIVE_WATCH=1 cargo test --features testutil --test reconcile_it live_watcher_smoke -- --nocaptureTests never touch the real ~/.claude: filesystem-touching logic runs against a
synthesized fake master in a tempdir, and system-touching code (launchctl,
exec, Keychain) sits behind traits so it's mockable and CI-safe.
Phase 2 (CLI v1): all four public commands, the hidden daemon and launch
entrypoints, launchd lifecycle, and shell-alias generation are implemented.
history.jsonl is treated as an ordinary shared symlink (advisory-lock
mitigation is deferred behind the Phase 1 append-test result).