Getting Started
This guide covers how to create .tool.ts configuration files for your CLI tools.
Prerequisites
Section titled “Prerequisites”Set up your project configuration first. See Project Configuration for instructions.
Bootstrap Install
Section titled “Bootstrap Install”To bootstrap a dotfiles project in the current directory, run:
curl -fsSL https://alexgorbatchev.github.io/dotfiles/install.sh | bashThe hosted installer provisions a dotfiles project in the current directory, creates a minimal dotfiles.config.ts when needed, and runs dotfiles generate for you.
Generated shell output includes # /path/to/tool.tool.ts attribution comments before emitted blocks, including generated .once/* helper scripts created from .once(...) shell configuration.
Load Generated Config
Section titled “Load Generated Config”With the default project layout, the generated zsh config lives at .generated/shell-scripts/main.zsh inside your dotfiles directory.
Add it to ~/.zshrc:
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
~/.bashrcor~/.profileto load the same environment.
if [ -f "$HOME/.dotfiles/.generated/shell-scripts/main.bash" ]; then # shellcheck disable=SC1090 . "$HOME/.dotfiles/.generated/shell-scripts/main.bash"fi
# ~/.profileif [ -n "${BASH_VERSION:-}" ] && [ -f "$HOME/.bashrc" ]; then . "$HOME/.bashrc"fiThen reload zsh:
source ~/.zshrcFile Structure
Section titled “File Structure”Tool configurations are placed in your toolConfigsDir (default: ~/.dotfiles/tools):
tools/├── fzf.tool.ts├── ripgrep.tool.ts└── dev/ ├── node.tool.ts └── rust.tool.tsFiles must be named {tool-name}.tool.ts and export a default using defineTool.
Obtain Tool Configurations
Section titled “Obtain Tool Configurations”Use dotfiles tool scaffold to provision starter configurations, or dotfiles tool add to download one published by a GitHub repository. The command reference describes accepted repository URLs and the required remote layout.
After adding a configuration, review it and run dotfiles generate to generate its shims and shell integration. Run dotfiles install <tool> to install it immediately, or use one of its generated shims to install on first use. See the post-addition workflow and load the generated shell configuration.
Minimal Configuration
Section titled “Minimal Configuration”import { defineTool } from "@alexgorbatchev/dotfiles";
export default defineTool((install, ctx) => install("github-release", { repo: "junegunn/fzf", }).bin("fzf"),);Complete Example
Section titled “Complete Example”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" })),);Available Methods
Section titled “Available Methods”install() returns a builder whose methods declare binaries, shell configuration,
symlinks, copies, hooks and platform overrides. They are listed in the
builder method table.
TypeScript Setup
Section titled “TypeScript Setup”Imports
Section titled “Imports”import { Architecture, defineTool, Platform } from "@alexgorbatchev/dotfiles";| Export | Description |
|---|---|
defineTool | Factory function to create tool configurations |
Platform | Enum: Linux, MacOS, Windows, All |
Architecture | Enum: X86_64, Arm64 |
Configuration-Only Tools
Section titled “Configuration-Only Tools”Tools that only contribute shell configuration (no binary installation):
export default defineTool((install) => install().zsh((shell) => shell.env({ FOO: "bar" })));Orphaned Artifact Cleanup
Section titled “Orphaned Artifact Cleanup”When a .tool.ts configuration file is removed, the next dotfiles generate removes everything dotfiles recorded creating for that tool: its shims, symlinks, completions, copies, templates, managed blocks, the directories it created once they are empty, and its install directory under paths.binariesDir with the downloaded binaries in it. Each removal is recorded in the registry, so dotfiles state log <tool> shows what happened to every file. 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.
Cleanup only removes what is still dotfiles’ own:
- A symlink is removed while it still points where dotfiles pointed it, including when that target was deleted along with the tool’s directory. A link that now points somewhere else, or a file or directory put in its place, is left alone with a warning.
- A copy or template you edited is moved aside to a
.bakfile rather than deleted. A copied file is left alone when a directory above it is no longer the one dotfiles copied into, such as a copied directory you replaced with a link to your own. - A directory the tool created is kept while it still holds files dotfiles did not create, and a directory that existed before the tool is never removed.
- A package installed by a package manager (
brew,apt,npm, …) or an app bundle placed in/Applicationsis left installed with a warning, because uninstalling it needs the tool’s configuration.dotfiles tool uninstallremoves it while the tool is still configured.
When something cannot be removed, generate reports the failure, exits non-zero, and keeps the records of what is left, so the next run retries it.
A directory under paths.binariesDir whose name matches no active tool and that the registry records nothing for is removed as well when it holds a current entry, the layout every install leaves. That is how the downloaded binaries of tools removed before dotfiles recorded these removals are cleaned up. paths.binariesDir/dotfiles, where the installer deploys the CLI itself, and anything else in paths.binariesDir are left alone.
Auto-Generated Types
Section titled “Auto-Generated Types”Running dotfiles generate writes everything type-checking needs under .generated/:
node_modules/@alexgorbatchev/dotfiles/— the authoring package’s declarations, also reachable from the project root through anode_modulessymlink the CLI createstool-types.d.ts— the registry of every configured binary name, including those of disabled tools, which givesdependsOn()its autocomplete and rejects a name no tool declarestsconfig.json— the program the CLI type-checks with:dotfiles.config.ts, every tool configs directory, the registry and the runtime globals, with the compiler options the declarations are written for and no Node or Bun types
If the project has no tsconfig.json, dotfiles generate writes one that only extends the CLI’s:
{ "extends": "./.generated/tsconfig.json"}Nothing has to be added by hand: the include list lives in the CLI-owned file and follows the configured tool directories. A tsconfig.json the CLI wrote before it owned one is updated to this form; a file you edited is left alone.
Type-Checking
Section titled “Type-Checking”dotfiles tool validate type-checks the configuration with that program, using the TypeScript 7 compiler provisioned like any other tool: dotfiles tool scaffold writes tools/typescript.tool.ts, which installs microsoft/typescript-go from its GitHub release, and dotfiles tool install typescript installs it. The compiler is declared with .bin("tsc", { shim: false }), so it is not put on PATH and cannot shadow the TypeScript your other projects use; tool validate runs it from the tool’s current directory. Until it is installed, tool validate reports that as an error rather than skipping the type-check. Your editor uses the same program through the extending tsconfig.json.
Common Type Errors
Section titled “Common Type Errors”// ❌ Missing required parameterinstall('github-release', {}) // Error: 'repo' is required
// ❌ Invalid parameter for methodinstall('brew', { repo: 'owner/tool' }) // Error: 'repo' not valid for brew
// ❌ String instead of enum.platform('macos', ...) // Error: use Platform.MacOS