Skip to content

Getting Started

This guide covers how to create .tool.ts configuration files for your CLI tools.

Set up your project configuration first. See Project Configuration for instructions.

To bootstrap a dotfiles project in the current directory, run:

Terminal window
curl -fsSL https://alexgorbatchev.github.io/dotfiles/install.sh | bash

The hosted installer uses Bun from PATH when available. Otherwise it checks for curl and unzip before prompting, bootstraps a temporary Bun, adds @alexgorbatchev/dotfiles to the local package.json without running your project’s lifecycle scripts, creates a minimal dotfiles.config.ts when needed, installs managed Bun, and runs dotfiles generate for you. Generated dotfiles shell output resolves Bun at runtime instead of pinning the temporary bootstrap Bun path, and the temporary bootstrap directory is cleaned up before exit even if a later step fails.

Generated shell output includes # /path/to/tool.tool.ts attribution comments before emitted blocks, including generated .once/* helper scripts created from .once(...) shell configuration.

With the default project layout, the generated zsh config lives at .generated/shell-scripts/main.zsh inside your dotfiles directory.

Add it to ~/.zshrc:

Terminal window
source "$HOME/.dotfiles/.generated/shell-scripts/main.zsh"

[!IMPORTANT] Configure bash even if your interactive shell is zsh. AI harnesses and other automation often start bash and rely on ~/.bashrc or ~/.profile to load the same environment.

~/.bashrc
if [ -f "$HOME/.dotfiles/.generated/shell-scripts/main.bash" ]; then
# shellcheck disable=SC1090
. "$HOME/.dotfiles/.generated/shell-scripts/main.bash"
fi
# ~/.profile
if [ -n "${BASH_VERSION:-}" ] && [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi

Then reload zsh:

Terminal window
source ~/.zshrc

Tool configurations are placed in your toolConfigsDir (default: ~/.dotfiles/tools):

tools/
├── fzf.tool.ts
├── ripgrep.tool.ts
└── dev/
├── node.tool.ts
└── rust.tool.ts

Files must be named {tool-name}.tool.ts and export a default using defineTool.

import { defineTool } from "@alexgorbatchev/dotfiles";
export default defineTool((install, ctx) =>
install("github-release", {
repo: "junegunn/fzf",
}).bin("fzf"),
);
import { defineTool } from "@alexgorbatchev/dotfiles";
export default defineTool((install, ctx) =>
install("github-release", {
repo: "BurntSushi/ripgrep",
})
.bin("rg")
.dependsOn("pcre2")
.symlink("./ripgreprc", "~/.ripgreprc")
.zsh((shell) => shell.env({ RIPGREP_CONFIG_PATH: "~/.ripgreprc" }).aliases({ rgi: "rg -i" })),
);

After calling install(), these methods are available:

MethodPurpose
.bin(name)Define binary name(s) to expose
.version(v)Set version ('latest' or specific)
.dependsOn(bin)Declare binary dependencies
.symlink(src, dest)Create config file symlinks
.hook(event, fn)Lifecycle hooks
.zsh(fn) / .bash(fn)Shell-specific configuration
.platform(p, fn)Platform-specific overrides
.sudo()Require an interactive sudo step
.disable()Skip tool during generation
.hostname(pattern)Restrict tool to specific hostname(s)
import { Architecture, defineTool, Platform } from "@alexgorbatchev/dotfiles";
ExportDescription
defineToolFactory function to create tool configurations
PlatformEnum: Darwin, Linux, Windows, MacOS
ArchitectureEnum: X86_64, Arm64

Tools that only contribute shell configuration (no binary installation):

export default defineTool((install) => install().zsh((shell) => shell.env({ FOO: "bar" })));

When a .tool.ts configuration file is removed, dotfiles generate automatically cleans up the corresponding generated shims and completions on the next run. Removing a .bin() declaration from an existing tool also removes that tool’s stale shim on the next dotfiles generate. No manual cleanup is needed.

Running dotfiles generate creates .generated/tool-types.d.ts with type-safe dependsOn() autocomplete for all your tool binaries. Standalone compiled-binary installs may generate additional supporting declaration files in .generated/, but you should still include only .generated/tool-types.d.ts in tsconfig.json.

In standalone-binary projects, dotfiles generate writes the supporting authoring declaration file automatically and wires it in for you. That means:

  • imports from the public authoring package typecheck without a local handwritten shim
  • nested helper modules that import those packages are supported too
  • your tsconfig.json still only needs .generated/tool-types.d.ts

Add to your tsconfig.json:

{
"include": ["tools/**/*.tool.ts", ".generated/tool-types.d.ts"]
}
// ❌ Missing required parameter
install('github-release', {}) // Error: 'repo' is required
// ❌ Invalid parameter for method
install('brew', { repo: 'owner/tool' }) // Error: 'repo' not valid for brew
// ❌ String instead of enum
.platform('macos', ...) // Error: use Platform.MacOS