You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dotctl/dotctl-roadmap.md

7.0 KiB

dotctl — Fresh Machine Bootstrap Roadmap

Goal

A single command on a fresh machine should clone a dotfiles repo and fully apply it:

dotctl apply https://github.com/user/dotfiles.git

No manual git clone. No rebuilding from source. No multi-step dance.


Current State Summary

Capability Status
init / add / link core loop Working
Symlink creation Working
Config stored at ~/dotfiles/dotctl/config.yaml Working
sync command (pull + push) ⚠️ Unstable — README warns against it
Bootstrap from existing repo Missing
Conflict detection on link Missing
Idempotent link (safe to re-run) Missing
One-liner install script Missing
Templating / per-machine config Not in scope (yet)
Secret management Not in scope (yet)

Phase 1 — Fix the Foundation (prerequisite for everything)

These are bugs/gaps that block safe automation.

Problem: Running link a second time likely fails or clobbers without warning if a target path already exists.

Fix: Before creating each symlink, check the target:

  • If missing → create symlink (happy path)
  • If already a symlink pointing to the correct source → skip, log "already linked"
  • If already a symlink pointing somewhere else → warn, skip unless --overwrite flag passed
  • If a real file/directory exists → back it up to <path>.dotctl.bak, then link (or skip with --no-backup)

Files to touch: cmd/link.go

Acceptance criteria: Running dotctl link twice on a clean setup produces no errors and no duplicate symlinks.


1.2 Fix or remove sync

Problem: The README actively warns against sync. It should either be fixed or removed so it doesn't cause data loss for new users.

Decision to make (pick one):

  • Option A — Fix it: Proper git pull → detect conflicts → commit changed files → push. Use go-git for in-process git operations instead of shelling out.
  • Option B — Remove it: Drop sync, document that users should manage the ~/dotfiles directory as a normal git repo. Add a note in README pointing to how to do git pull and then dotctl link.

Recommendation: Option B now, Option A later in Phase 3. It's safer to remove a broken command than ship a half-working one.


1.3 Validate that config round-trips cleanly

Problem: The tracked file list lives in ~/dotfiles/dotctl/config.yaml. On a fresh machine, this file needs to already exist in the cloned repo for bootstrap to work. Need to confirm this file is actually committed and not gitignored.

Fix: Add a note in .gitignore explicitly not ignoring dotctl/config.yaml. Add a check in init that warns if the config file would be gitignored.


Phase 2 — The Bootstrap Command (core deliverable)

2.1 dotctl apply <repo-url>

This is the main feature. It should:

  1. Check if ~/dotfiles already exists
    • If yes and it's a git repo → git pull (or prompt user)
    • If yes but not a git repo → error with clear message
    • If no → git clone <repo-url> ~/dotfiles
  2. Read ~/dotfiles/dotctl/config.yaml (fail clearly if not found — tells user their repo isn't set up for dotctl)
  3. Run the equivalent of dotctl link with idempotent behavior from Phase 1.1
  4. Print a summary: N linked, M skipped, K backed up

Flags:

  • --overwrite — overwrite existing files instead of backing up
  • --dry-run — print what would happen without touching the filesystem
  • --no-backup — skip backups, just skip conflicts

Files to touch: New cmd/apply.go

Acceptance criteria: On a machine with nothing but Go installed and git in PATH, running dotctl apply https://github.com/user/dotfiles.git produces a fully linked dotfiles setup.


2.2 One-liner install + apply script

The bootstrap UX needs to work before dotctl itself is installed. Options:

Option A — go install (simplest):

go install github.com/Marcusk19/dotctl@latest && dotctl apply https://github.com/user/dotfiles.git

Requires Go on the machine. Works great for developer setups.

Option B — Shell script + prebuilt binary:

curl -fsSL https://raw.githubusercontent.com/Marcusk19/dotctl/main/install.sh | bash -s -- https://github.com/user/dotfiles.git

The script: detects OS/arch → downloads the correct binary from GitHub releases → runs dotctl apply <repo>. No Go required.

Recommendation: ship both. go install for devs, the curl script for fresh machines where Go may not be present. goreleaser is already set up, so binary releases exist — just need the install script.

Files to add: install.sh in repo root


Phase 3 — Quality of Life (after core bootstrap works)

3.1 Fix sync properly

With go-git as a dependency (or shelling to git with proper error handling):

  • dotctl sync → pull remote changes, re-run link, push any local changes
  • Detect and surface merge conflicts clearly instead of silently failing

3.2 dotctl status

Shows current state of all tracked files:

nvim        → ~/.config/nvim         [linked ✓]
zshrc       → ~/.zshrc               [linked ✓]
kitty       → ~/.config/kitty        [CONFLICT — real file exists]
tmux.conf   → ~/.tmux.conf           [broken symlink]

3.3 dotctl remove <path>

Removes a tracked file from the manifest and optionally replaces the symlink with the real file.


3.4 dotctl list

Prints all tracked entries from config — useful for auditing before running apply on a new machine.


Phase 4 — Advanced (optional, post-stabilization)

Feature Notes
Per-machine profiles Tag entries in config with profiles: [work, home]; pass --profile to apply
Templating Go text/template over files with a .tmpl extension — render before linking
Secret redaction Warn when a tracked file contains patterns that look like secrets (API keys, tokens)
XDG-aware paths Auto-resolve $XDG_CONFIG_HOME instead of hardcoding ~/.config

Implementation Order

Phase 1.1 → idempotent link        (12 days)
Phase 1.2 → remove/fix sync        (0.5 days)
Phase 1.3 → config gitignore audit (0.5 days)
Phase 2.1 → dotctl apply command   (23 days)
Phase 2.2 → install.sh script      (1 day)
Phase 3.x → status, list, remove   (23 days)
Phase 4.x → profiles, templating   (future)

Definition of Done (for "point at a repo and go")

  • install.sh downloads the correct binary for current OS/arch
  • dotctl apply <url> clones repo if not present, reads config, links all tracked files
  • Running apply twice produces no errors
  • Existing files are backed up, not silently overwritten
  • --dry-run works and shows exactly what would happen
  • README updated with the new one-liner bootstrap flow
  • At least one end-to-end test that: clones a test dotfiles repo → runs apply → asserts symlinks exist