Installation Experience Excellence: a real wizard, a real uninstall
DevForgeKit's installer went from a collection of shell scripts to a professional install experience: an interactive wizard, real download sizes, resumable installs, and a devforgekit uninstall command that never touches your machine without asking.

The bootstrap script worked. It provisioned Homebrew, runtimes, dotfiles, editors, and services in one idempotent run. What it didn't do was feel like software you'd trust on a machine you cared about: no preview of what was about to happen, no real sense of how much would download, and no way back out if you changed your mind. This release closes that gap.
An interactive wizard, not a surprise
Run ./devforgekit install with no flags in a real terminal and, on a first-ever install, a wizard walks through exactly what's about to happen instead of silently installing everything. Pick Minimal, Recommended, Full, or Custom. Custom opens a category checklist where each category carries its own description, so you know why it exists before you check it.
Every explicit --profile flag, --yes, --dry-run, or non-interactive/CI invocation skips the wizard entirely and installs exactly what was asked for. Nothing about scripted or unattended installs changes.
$ ./devforgekit install
? Choose an install profile
1) Minimal — bare essentials
2) Recommended — everyday tooling
3) Full — everything
4) Custom — pick categories
✓ Homebrew formulae: 48 ✓ Casks: 6
✓ VS Code extensions: 12 ✓ Estimated download: ~7.4 GB
Continue with this installation?Real download sizes, never fabricated
Homebrew's own JSON metadata has no size field for formulae or casks, so the wizard doesn't pretend to know. It resolves each package's bottle or cask download URL and issues a parallel HEAD request per package, summing real Content-Length headers into one honest total. Heavy packages (Flutter, Android Studio, full database servers) are flagged individually with their measured size, not a guess.
If a HEAD request fails or times out, that package is counted as unmeasured and the total says so explicitly, '~6.1 GB (partial — 2 packages unmeasured)', rather than silently under-reporting.
Failures don't stop the install, and they don't get forgotten
A single package failing to install used to mean staring at a stack trace. Now the installer continues past it, finishes everything else, and prints a clear Succeeded/Failed summary at the end. If anything failed, it points straight at the fix: devforgekit repair install.
That same install state persists to disk, so a run that's interrupted (a dropped connection, a closed laptop lid) can resume exactly where it left off next time, skipping everything that already succeeded instead of starting over.
$ devforgekit repair install
Scanning CLI installation…
✗ 2 packages failed in the last run: flutter, postgresql@16
Retrying failed packages only…
✓ flutter installed
✓ postgresql@16 installed
CLI install repaired.Verification that actually verifies
Post-install verification used to check that a few files existed. It now runs the real commands: devforgekit --version, devforgekit check, and a forced dashboard-fallback path, actually executing them and checking exit codes, not inferring success from a symlink being present.
First-run finishes with a welcome screen instead of dropping straight into the dashboard: your health score, the tools that verified successfully, and a short menu to launch the dashboard, run doctor, or generate a first project.
A real uninstall, and the incident that shaped it
devforgekit uninstall shows a checklist (installed packages, VS Code/Cursor extensions, configuration, services) and previews exactly what it's about to remove before it removes anything. Configuration files are backed up with a timestamp, never deleted outright.
That design wasn't the first draft. An early version leaned on the CLI's existing confirm() helper, which auto-confirms when stdin isn't an interactive terminal: the right behavior for unattended installs, and the wrong one for anything destructive. It surfaced during our own testing, on a real machine, before this ever shipped.
The fix wasn't a one-line patch. Every destructive operation (brew uninstall, service stops, file removal) now routes through dedicated dfk_run_destructive and dfk_remove_file primitives. Interactive execution behaves as before; non-interactive execution without an explicit flag refuses to run and exits safely; a DEVFORGEKIT_TEST_MODE lets the full destructive path be exercised in tests without ever touching a real machine. Five regression tests pin all of it down, including the exact failure mode that motivated the change: echo "n" | devforgekit uninstall must never perform a real uninstall.
$ devforgekit uninstall
Remove:
[x] Installed packages (from your Brewfile)
[x] VS Code extensions
[x] Cursor extensions
[x] Configuration (.zshrc, .gitconfig, mise.toml, editor settings)
[x] Services (stop PostgreSQL/MySQL/Redis)
Continue?
$ devforgekit uninstall --all --force # non-interactive, explicitWhat's next
Homebrew and npm distribution were the next milestone. This release made source installs feel finished first, and both channels have since shipped: npm install -g devforgekit and brew install nouradinabdurahman/devforgekit/devforgekit are now the recommended way to install. The installation page walks through the full wizard, verification, and uninstall flow, and the CommandReference doc covers every flag for scripted use.