Skip to content

Commands

All commands are available via:

bash
bunx @dotformat/cli <command>
# or from a clone:
bun bin/dotfiles.ts <command>

Quick Reference

CommandPurposeKey Flags
collectMachine snapshot → .dotf report--no-redact, --slim, -o
backupCopy config files → structured directory--archive, --only, --skip, --no-redact, -o
scanStandalone sensitivity scanpath argument
restoreRestore backup → live locations--pick, --dry-run
diffBackup vs live system--section
statusQuick backup summary
compareDiff two .dotf filespositional file paths
listQuery section from latest reportfuzzy section name

collect

Generate a structured .dotf machine snapshot. This is the primary "what's on my machine?" command.

bash
dotfiles collect [--no-redact] [--slim] [-o path]

Flags

FlagTypeDefaultDescription
--no-redactbooleanfalseInclude sensitive values as-is, skip all redaction
--slimbooleanfalseTruncate content sections to 10 lines. Appends ... (N more lines) to truncated sections. Reduces output by ~65% — useful for feeding to AI tools
-o <path>stringautoCustom output directory

Behavior

  1. Resolves output directory (see Output Path Logic)
  2. Runs all collectors in parallel via Promise.allSettled — one collector failing does not abort the report
  3. Merges all fulfilled results into a single sections map
  4. If redaction is enabled (default):
    • Scans each content section for sensitive patterns
    • Drops sections where action is skip (e.g., private keys)
    • Applies [REDACTED] replacements where action is redact
  5. If --slim is enabled, truncates content sections to 10 lines
  6. Stringifies to .dotf format via @dotformat/core
  7. Writes to <hostname>-YYYYMMDDHHMMSS.dotf
  8. Prints sensitivity report if any findings

Collectors

The collect command runs these collectors in parallel:

CollectorSourceType
collectMetahostname, OS, dateHand-written
registryCollector(registryEntries)All 23 registry entriesGenerated from registry
collectSsh~/.ssh/config parsedHand-written (structured items)
collectOllamaollama list outputHand-written (command)
collectApps/Applications, Raycast, AltTabHand-written (macOS only)
collectHomebrewbrew list --formula/--caskHand-written (macOS only)

Example Output

bash
$ dotfiles collect
Report saved to: reports/MacBook-Pro-20260407143022.dotf

 Sensitivity report:
  HIGH   npm.config                     auth token redacted
  MEDIUM ssh.config                     IP address included

  1 items redacted. Use --no-redact to include all.
bash
$ dotfiles collect --slim -o /tmp
Report saved to: /tmp/MacBook-Pro-20260407143022.dotf

backup

Copy real config files into a structured directory tree. Unlike collect (which produces a single text file), backup creates actual file copies organized by category.

bash
dotfiles backup [--no-redact] [--archive] [--only <categories>] [--skip <categories>] [-o path]

Flags

FlagTypeDefaultDescription
--no-redactbooleanfalseSkip sensitivity redaction
--archivebooleanfalseAfter creating backup dir, compress to .tar.gz via system tar, then remove the directory
--only <list>comma-separatedallInclude only these categories (e.g., --only ai,shell)
--skip <list>comma-separatednoneExclude these categories (e.g., --skip editor,npm)
-o <path>stringautoCustom output directory

Available Categories

ai, shell, git, editor, terminal, ssh, npm, bun

Behavior

  1. Resolves output directory
  2. Creates timestamped backup directory: backup-<hostname>-YYYYMMDDHHMMSS/
  3. Filters backup sources by --only / --skip
  4. For each source entry:
    • File entries: reads file → scans for sensitivity → applies custom redaction if defined → applies pattern redaction → writes to backup dest
    • Dir entries: copies all files recursively (using Bun.Glob with dot: true for dotfiles)
  5. If --archive: runs tar czf on the backup dir, removes the original directory
  6. Prints summary: file count per category
  7. Prints sensitivity report

Example Output

bash
$ dotfiles backup --only ai,shell
Backup saved to: reports/backup-MacBook-Pro-20260407143200
  8 files across: ai (7), shell (1)

$ dotfiles backup --archive
Archive saved to: reports/backup-MacBook-Pro-20260407143200.tar.gz
  15 files across: ai (7), shell (1), git (3), editor (2), terminal (1), bun (1)

Special Redaction

Some entries have custom redaction functions in addition to pattern-based scanning:

EntryCustom Redaction
ssh.configredactSshConfig() — replaces HostName values with [REDACTED]
npm.configredactNpmTokens() — replaces _authToken=... values with [REDACTED]

scan

Standalone sensitivity scanner. Useful for checking any file or directory for secrets before sharing.

bash
dotfiles scan [path]

Arguments

ArgumentDefaultDescription
path. (current directory)File or directory to scan

Behavior

  • Single file: scans the file, reports findings
  • Directory: recursively scans all files using Bun.Glob('**/*') with dot: true
    • Skips node_modules/ and .git/ paths
    • Skips files larger than 1 MiB
  • Findings are sorted by severity (HIGH → MEDIUM → LOW)
  • Each finding shows: line number, severity, pattern label, and matched text (truncated to 40 chars)

Example Output

bash
$ dotfiles scan ~/.ssh/config

~/.ssh/config
  L3 [MEDIUM] IP address: 192.168.1.***...
  L7 [MEDIUM] email address: user@exam...

 Sensitivity report:
  MEDIUM ~/.ssh/config                  IP address redacted

  1 items redacted. Use --no-redact to include all.

restore

Restore backed-up files to their original locations on the machine. Full safety features: dry run, interactive picker, pre-restore snapshots, conflict prompts.

bash
dotfiles restore <backup-path> [--pick] [--dry-run]

Arguments & Flags

Argument/FlagTypeRequiredDescription
<backup-path>stringyesPath to a backup directory
--pickbooleannoInteractive category selection (checkbox UI)
--dry-runbooleannoPreview the restore plan without writing any files

Restore Plan

Before any writes, the CLI builds a restore plan by scanning the backup directory and mapping each file to its target location:

StatusMeaningBehavior
newFile exists in backup but not on machineWrite directly
sameBackup content matches machine content (via Bun.hash())Skip silently
conflictBoth exist but differPrompt user
redactedBackup file contains [REDACTED]Skip with message

Conflict Prompt

When a file exists on both sides with different content:

KeyAction
oOverwrite this file
sSkip this file
dShow inline diff, then ask again
aOverwrite all remaining conflicts
lSkip all remaining conflicts

Pre-Restore Snapshot

Before overwriting any conflicting files, the CLI automatically saves the current versions of those files to a pre-restore-YYYYMMDDHHMMSS/ directory. This snapshot uses the same backup format — you can restore from it with dotfiles restore.

.local Override Pattern

If a backup contains shell/.zshrc.local, it restores to ~/.zshrc.local — the .local suffix maps to the same target directory as the base file. This supports the common pattern of having machine-specific overrides alongside shared configs.

Category Picker (--pick)

Shows a checkbox list of available categories with file counts. Select which categories to restore:

bash
$ dotfiles restore ./backup --pick
? Select categories to restore:
  [x] ai (7 files)
  [ ] shell (1 file)
  [x] git (3 files)
  [ ] editor (2 files)

Example Output

bash
$ dotfiles restore ./backup --dry-run

Dry run no files will be changed:

  [NEW]        editor/zed/settings.json ~/.config/zed/settings.json
  [CONFLICT]   shell/.zshrc ~/.zshrc
  [SAME]       git/.gitconfig ~/.gitconfig
  [REDACTED]   ssh/config ~/.ssh/config

  4 files total: 1 new, 1 conflicts, 1 unchanged, 1 redacted (skipped)

diff

Compare the backup state against the current live system. Answers: "what changed since last backup?"

bash
dotfiles diff [path] [--section <name>]

Arguments & Flags

Argument/FlagTypeDefaultDescription
[path]stringauto-detectBackup directory path. If omitted, finds the latest backup-* directory
--section <name>stringallFilter to a specific category (e.g., ai, shell, git)

Behavior

  • Builds a restore plan (same as restore) to determine file statuses
  • Groups entries by category
  • Color-codes output (TTY-aware — no colors in pipes):
    • yellow: modified (content differs)
    • green: unchanged
    • blue: new (in backup, missing on machine)
    • gray: redacted
  • Uses Bun.color(name, "ansi-256") for terminal colors

Auto-Find Latest Backup

If no path is given, diff searches the resolved output directory for directories matching backup-*, sorted by name (descending), and uses the first match.

Example Output

bash
$ dotfiles diff

Comparing backup against live system:

  ai/
    ai/claude/settings.json modified
    ai/claude/CLAUDE.md unchanged
    ai/cursor/mcp.json unchanged
  shell/
    shell/.zshrc modified
  git/
    git/.gitconfig unchanged

  5 files: 2 modified, 3 unchanged
bash
$ dotfiles diff --section ai

Comparing backup against live system:

  ai/
    ai/claude/settings.json modified
    ai/claude/CLAUDE.md unchanged

  2 files: 1 modified, 1 unchanged

Scope Note

diff compares only files represented in the backup. It does not discover new files that exist on the machine but were not captured in the backup. For full discovery, run collect and use compare.


status

Quick summary of backup state — like git status for your configs.

bash
dotfiles status

Behavior

  1. Finds the latest backup directory (same logic as diff)
  2. Calculates backup age from directory modification time
  3. Builds restore plan to count statuses
  4. Prints summary

Age Display

AgeDisplay
< 60 minutesNm ago
< 24 hoursNh ago
>= 24 hoursNd ago

Example Output

bash
$ dotfiles status
Last backup: 2h ago (backup-MacBook-Pro-20260407120000)
  15 files tracked: 2 modified, 13 unchanged

Modified since backup:
  shell/.zshrc
  ai/claude/settings.json
bash
$ dotfiles status
Last backup: 5m ago (backup-MacBook-Pro-20260407143200)
  15 files tracked: 0 modified, 15 unchanged

Everything up to date.

compare

Structured diff between two .dotf report files. Powered by @dotformat/core's compare() and formatDiff().

bash
dotfiles compare [file1] [file2]

Arguments

ArgumentRequiredDescription
file1noPath to first .dotf file
file2noPath to second .dotf file

If both are omitted, compare finds the two newest .dotf files in <cwd>/reports/ (sorted by modification time).

Behavior

  • Parses both files via @dotformat/core's parse()
  • Computes structured diff via compare()
  • Formats with formatDiff() with color enabled
  • Labels are derived from filenames (without .dotf extension)

Example

bash
$ dotfiles compare reports/MacBook-20260401.dotf reports/MacBook-20260407.dotf

WARNING

compare only looks in <cwd>/reports/ when auto-detecting files. It does not search ~/Downloads or other directories. Provide explicit paths if your reports are elsewhere.


list

Print a section from the most recent .dotf report. Supports fuzzy matching on section names.

bash
dotfiles list <section>

Arguments

ArgumentRequiredDescription
sectionyesSection name or partial match

Fuzzy Matching

The query is matched against section names using two strategies:

  1. Substring match: brew matches apps.brew.formulae and apps.brew.casks
  2. Dot-segment match: claude matches ai.claude.settings, ai.claude.skills, ai.claude.md

All matching sections are printed in .dotf format.

Available Sections

These are the section IDs used in .dotf reports:

SectionSource
metaHostname, OS, date
ai.claude.settingsClaude permissions, plugins
ai.claude.skillsClaude skills directory listing
ai.claude.mdCLAUDE.md content
ai.cursor.mcpCursor MCP config
ai.cursor.skillsCursor skills listing
ai.gemini.settingsGemini preferences
ai.gemini.skillsGemini skills listing
ai.gemini.mdGEMINI.md content
ai.windsurf.mcpWindsurf MCP config
ai.windsurf.skillsWindsurf skills listing
ai.ollama.modelsOllama model list (name, size, modified)
shell.zshrc.zshrc content
git.config.gitconfig content
git.ignore.gitignore_global content
gh.configGitHub CLI config
editor.zedZed settings
editor.cursorCursor editor settings
editor.nvimNeovim init.lua
editor.vimrc.vimrc
terminal.p10kP10k metadata (exists, line count)
terminal.tmuxtmux.conf content
ssh.hostsSSH hosts table (host, hostname, identity)
ssh.configSSH config content
npm.config.npmrc content
bun.config.bunfig.toml content
apps.raycastRaycast installed status
apps.alttabAltTab installed + prefs
apps.macosmacOS /Applications listing
apps.brew.formulaeHomebrew formulae list
apps.brew.casksHomebrew casks list

Example

bash
$ dotfiles list brew
[apps.brew.formulae]
bat
eza
fd
fzf
...

[apps.brew.casks]
alt-tab
firefox
raycast
...
bash
$ dotfiles list claude
[ai.claude.settings]
enabledPlugins = ...
permissions = ...

[ai.claude.skills]
superskill.md
web-dev.md

If no sections match:

bash
$ dotfiles list foo
No sections matching "foo".
Available sections: meta, ai.claude.settings, ai.claude.skills, ...

Output Path Logic

All commands that write files share the same output directory resolution:

PriorityConditionOutput
1-o <path> flag providedExplicit path
2.git/HEAD exists in current working directory<cwd>/reports/
3Otherwise (global/standalone run)~/Downloads

This means:

  • Inside a cloned repo: reports and backups go to reports/ — ideal for committing to git
  • Running globally (via bunx): outputs go to ~/Downloads — easy to find and share
  • Explicit -o: always wins