Metadata-Version: 2.4
Name: dotgarden
Version: 0.3.0
Summary: Manage dotfiles: register configs, bootstrap symlinks, and keep everything in sync.
Project-URL: Homepage, https://github.com/andrewlook/dotgarden
Project-URL: Repository, https://github.com/andrewlook/dotgarden
Author: Andrew Look
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: System :: Installation/Setup
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Requires-Dist: pyyaml>=6.0
Provides-Extra: test
Requires-Dist: pytest; extra == 'test'
Description-Content-Type: text/markdown

<!--
  This README is published to PyPI as the project's long description. PyPI
  does not resolve relative markdown links against the source repo, so every
  internal doc link below uses an absolute https://github.com/... URL.
  Please keep them absolute — don't "tidy" them back to repo-relative paths.
-->

# dotgarden

Manage dotfiles by moving them into a git-tracked repo and pointing `$HOME` at
the repo-managed copies. `dotfile register` relocates a live config into the
repo and leaves a symlink behind; `dotfile bootstrap` replays those symlinks
(plus OS/profile variants) on any machine. Ships the `dotfile` CLI.

![dotfile status output showing managed symlinks grouped by category](https://github.com/andrewlook/dotgarden/raw/main/dotgarden-status.png)

## Install

```bash
uv tool install dotgarden
# or
pipx install dotgarden
# or
pip install dotgarden
```

## Quick start

Clone the **[dotgarden-template](https://github.com/andrewlook/dotgarden-template)**
repo — a working dotfiles layout that exercises every `dotfile` feature.

```bash
git clone https://github.com/andrewlook/dotgarden-template.git ~/dotfiles
cd ~/dotfiles
dotfile bootstrap --os macos        # or --os linux
```

### What's in the template

```
dotfiles/
├── .gitconfig                      root dotfile → ~/.gitconfig
├── .macos.gitconfig                OS variant, sourced via ~/.gitconfig.local
├── .linux.gitconfig
├── .zprofile
├── .macos.zprofile
├── .tmux.conf
├── .config/                        auto-symlinked 1:1 into ~/.config/
│   ├── fish/
│   │   ├── config.fish
│   │   └── config.macos.fish       nested variant (BASE.MOD.EXT)
│   └── ghostty/
│       └── config
├── _cursor/                        registered: target lives outside ~/.config/
│   ├── settings.json
│   └── keybindings.json
├── __registry__.yaml
└── bootstrap.sh                    curl-pipe-sh installer for new machines
```

Everything at the repo root (`.gitconfig`, `.zprofile`, …) and every
top-level child of `.config/` is placed by convention. The registry handles
the rest — here, just Cursor, whose real target path is nowhere near
`~/.config/`:

```yaml
# __registry__.yaml
os: [macos, linux]
profiles: [work, home]

cursor:
  macos:
  - _cursor/settings.json: ~/Library/Application Support/Cursor/User/settings.json
  - _cursor/keybindings.json: ~/Library/Application Support/Cursor/User/keybindings.json
```

### What bootstrap produces

```
$ dotfile bootstrap --os macos
  common
    ✓ ~/.gitconfig        ->  ~/dotfiles/.gitconfig
    ✓ ~/.macos.gitconfig  ->  ~/dotfiles/.macos.gitconfig
    ✓ ~/.zprofile         ->  ~/dotfiles/.zprofile
    ✓ ~/.config/fish      ->  ~/dotfiles/.config/fish
    ✓ ~/.config/ghostty   ->  ~/dotfiles/.config/ghostty

  registered
    ✓ ~/Library/Application\ Support/Cursor/User/settings.json
        ->  ~/dotfiles/_cursor/settings.json

  local
    ✓ ~/.gitconfig.local
    ✓ ~/.config/fish/config.fish.local

✓ Bootstrap complete (8 created)
```

`$HOME` is now a set of symlinks pointing back at the repo, plus a few
generated `.local` files that source the right OS/profile variants:

```
$ ls -l ~/.gitconfig ~/.config/ghostty
~/.gitconfig       -> ~/dotfiles/.gitconfig
~/.config/ghostty  -> ~/dotfiles/.config/ghostty

$ cat ~/.gitconfig.local
# Auto-generated by dotfile bootstrap. Do not edit.
[include]
  path = ~/.macos.gitconfig
```

Edits in either location track together — they're the same inode. See
[GUIDE.md](https://github.com/andrewlook/dotgarden/blob/main/GUIDE.md) for
the hands-on walkthrough.

## Commands

| Command | Description |
|---------|-------------|
| `dotfile bootstrap` | Link files in `$HOME` to the repo-managed versions and generate `.local` include files |
| `dotfile status` | Check health of all managed symlinks |
| `dotfile register` | Move a config into the repo and symlink it back |
| `dotfile unregister` | Remove a config from management |
| `dotfile specialize` | Scaffold OS/profile variant files and wire their `.local` include |
| `dotfile list` | List all managed files |
| `dotfile doctor` | Find and remove stale symlinks |
| `dotfile env` | Show current OS, profile, and overlay |
| `dotfile ids` | Print entry IDs (for scripting) |

### `dotfile bootstrap`

```
dotfile bootstrap --os <macos|linux> [--profile <name>] [--overlay <dir>] [--dry-run]
```

Runs every symlink and `.local` generator from a clean slate. Safe to re-run.

- `--os` — required on first run; remembered in `~/.dotfiles_env` after.
- `--profile` — activates a profile's variant files and registry entries.
- `--overlay` — layers a second repo on top (see [GUIDE.md § Overlay](https://github.com/andrewlook/dotgarden/blob/main/GUIDE.md#9-overlay--carve-out-private-content)).
- `--dry-run` — print the plan without touching the filesystem.
- `--skip-registry` — only handle root + `.config/*` conventions, skip registered entries.
- `--skip-unsupported` — silently skip `.local` generation for tool types with no known include syntax.

Existing non-symlink files at a link location are preserved as `<path>.bak`
before being replaced.

### `dotfile register`

```
dotfile register <path> [--category <name>] [--os <os>] [--profile <name>] [--name <file>] [--overlay <dir>] [--force] [--dry-run] [-y]
```

Moves `<path>` into the repo (under `_<category>/` or the repo root) and
creates a symlink back. Errors if the destination already exists unless you
pass `--force`.

- `--category` — target subdirectory in the repo (auto-detected from the source path if omitted).
- `--os` / `--profile` — scope the entry so bootstrap only links it on matching machines.
- `--name` — rename the file inside the repo.
- `--overlay` — write into an overlay repo instead of the main one.
- `--force` — overwrite an existing registration or repo file.
- `-y` — skip the confirmation prompt.

### `dotfile specialize`

```
dotfile specialize <os|profile> <dotfile> [--dry-run]
```

Scaffolds variant files for an existing base dotfile and appends the `.local`
include line so bootstrap can generate the override file.

Works on root paths (`.gitconfig`) and nested paths under `.config/<tool>/`
(e.g. `.config/fish/config.fish`). Variant names come from the `os:` and
`profiles:` lists in `__registry__.yaml`. Idempotent — safe to re-run.

## Documentation

- [GUIDE.md](https://github.com/andrewlook/dotgarden/blob/main/GUIDE.md) —
  hands-on walkthrough: starting a repo, registering your first files,
  specializing for OS/profile, setting up an overlay
- [Starter template](https://github.com/andrewlook/dotgarden-template) — clone
  this to begin a new dotfiles repo
- Source and issue tracker:
  https://github.com/andrewlook/dotgarden

## Development

See [CONTRIBUTING.md](https://github.com/andrewlook/dotgarden/blob/main/CONTRIBUTING.md) for setup, testing (`mise run test`,
`./test-docker`), and the publish flow. The package layout, entry point
(`dotgarden.cli:main`), and test harness all live in this repo — edits
happen here directly.

The `examples/starter/` directory is mirrored to
[`andrewlook/dotgarden-template`](https://github.com/andrewlook/dotgarden-template)
as the clone-ready starting point documented in Quick start above.

## License

MIT — see [LICENSE](https://github.com/andrewlook/dotgarden/blob/main/LICENSE).
