Metadata-Version: 2.4
Name: dotpilot
Version: 0.2.0
Summary: Symlink-based dotfiles manager with auto-sync
Author: Ryan Munro
Author-email: Ryan Munro <500774+munro@users.noreply.github.com>
License-Expression: MIT
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: System :: Installation/Setup
Classifier: Topic :: System :: Systems Administration
Classifier: Typing :: Typed
Requires-Dist: click>=8.0
Requires-Dist: rich>=13.0
Requires-Python: >=3.12
Project-URL: Homepage, https://github.com/Submersible/dotpilot
Project-URL: Issues, https://github.com/Submersible/dotpilot/issues
Project-URL: Repository, https://github.com/Submersible/dotpilot
Description-Content-Type: text/markdown

# dotpilot

Symlink-based dotfiles manager. Your repo mirrors your home directory — no `dot_` prefixes, no templates, no source state. Edit a file, it's already applied.

```
uvx dotpilot@latest
```

Requires [uv](https://docs.astral.sh/uv/getting-started/installation/). Install it with:

```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```

## Why dotpilot?

Most dotfile managers copy files and require you to re-run a command after every edit. dotpilot **symlinks** — your dotfiles repo IS your home directory. Change a file in `~/dotfiles/.zshrc`, and `~/.zshrc` updates instantly because it's a symlink.

|  | dotpilot | chezmoi | GNU Stow | bare git |
|---|---|---|---|---|
| Edits apply instantly | Yes (symlinks) | No (must re-apply) | Yes (symlinks) | Yes |
| Repo structure | Mirrors ~/ | `dot_`, `private_`, `executable_` prefixes | Mirrors ~/ | Mirrors ~/ |
| New machine setup | `uvx dotpilot init` | `chezmoi init` | Manual clone + stow | Manual clone |
| Dry-run by default | Yes | No | No | N/A |
| Tracks what you're NOT managing | `dotpilot untracked` | No | No | No |
| Auto-sync from remote | Built-in cron | External | External | External |
| Auto-backup before apply | Yes | No | No | No |
| Templating | No | Yes (Go templates) | No | No |
| Secret management | No | Yes | No | No |
| Dependencies | Python (uv) | None (Go binary) | Perl | Git |

dotpilot trades templating and secrets for **simplicity**. If you need machine-specific config, use `.localrc` patterns or `.overwrite` files. If you need secrets, use a separate tool. Most people don't need either.

## Quick start

```bash
# New machine — clone, then review before applying
uvx dotpilot init git@github.com:you/dotfiles.git
dotpilot apply               # dry-run: shows what would change
dotpilot apply --apply       # back up + symlink everything

# Day-to-day
dotpilot status            # sync status (fetches from remote)
dotpilot track ~/.bashrc   # start managing a file
dotpilot sync --apply      # pull latest from origin
dotpilot diff              # uncommitted changes
```

## Commands

All commands default to `~/dotfiles`. Override with `--dotfiles DIR`. Use `-h` on any command for help.

| Command | Description |
|---|---|
| `init <repo>` | Clone a dotfiles repo and dry-run apply |
| `apply` | Symlink dotfiles into ~/ (dry-run by default, auto-backs up on `--apply`) |
| `sync` | Fetch and fast-forward merge from origin |
| `track <path>` | Start tracking a file — moves it to repo, symlinks back |
| `untrack <path>` | Stop tracking — removes symlink, moves file back |
| `untracked` | List dotfiles in ~/ and ~/.config you're not managing |
| `status` | Git sync status — fetches remote, shows dirty/ahead/behind |
| `diff` | Show uncommitted changes in the dotfiles repo |
| `backup` | Back up all managed dotfiles from ~/ into a timestamped directory |
| `restore <dir>` | Restore dotfiles from a backup directory |
| `doctor` | Check git, repo, SSH keys, upstream config |
| `completion` | Install zsh completions |
| `uninstall` | Remove symlinks, restore files, delete the dotfiles repo |
| `cron` | Set up auto-sync every 30 minutes |

Every mutating command is **dry-run by default**. Pass `--apply` to execute. Add `-v` to `apply` for verbose output.

## How it works

Your dotfiles live in a git repo (default `~/dotfiles`). dotpilot creates symlinks from `~/` into that repo.

```
~/dotfiles/.zshrc  ←symlink←  ~/.zshrc
~/dotfiles/.config/nvim  ←symlink←  ~/.config/nvim
```

Special file conventions:

- **`.overwrite` suffix** — copied instead of symlinked, for files that don't work as symlinks (e.g. `.config/git/gitk.overwrite`)
- **`.delete` suffix** — removes the corresponding file from `~/` (e.g. `.vimrc.delete` removes `~/.vimrc`)
- **`.dotpilotignore`** — fnmatch patterns for files to skip (one per line, `#` comments). `.gitignore` patterns are also respected.

## Backup and restore

`apply --apply` automatically creates a backup before making changes. Backups are stored inside the dotfiles repo as `dotfiles-backup-<timestamp>/`.

```bash
dotpilot backup                      # manual backup
dotpilot backup -o /tmp              # backup to custom location
dotpilot restore ./dotfiles-backup-* # dry-run: show what would change
dotpilot restore ./dotfiles-backup-* --apply  # restore files
```

Restore is symlink-aware — if symlinks are still in place, it writes through them into the repo. If symlinks are gone (e.g. after uninstall), it copies directly to `~/`.

## Uninstall

```bash
dotpilot uninstall           # dry-run: shows symlinks, cron, unpushed warnings
dotpilot uninstall --apply   # restore files, remove cron, delete repo
```

Warns about uncommitted changes and unpushed commits before deleting anything. Removes the cron job if one is installed.

## Auto-sync

The `cron` command installs a job that runs every 30 minutes (configurable with `--schedule`):

```bash
dotpilot cron               # dry-run: shows what cron entry would be added
dotpilot cron --apply        # install the cron job
dotpilot cron --apply --remove  # remove it
```

The cron job runs `uvx dotpilot@latest sync --apply --auto-apply`, which fetches from origin, fast-forward merges, and re-applies symlinks if anything changed.

If the working directory is dirty or the merge isn't a fast-forward, sync bails out — it won't clobber your local changes.

## License

MIT
