2 releases
| 0.1.5 | Apr 24, 2026 |
|---|---|
| 0.1.0 | Apr 24, 2026 |
#156 in FFI
37KB
390 lines
profilectl
Cross-platform dotfiles automation for macOS, Linux, and Windows, powered by Rust.
Manage your development environment through profiles — declarative TOML files that describe your symlinks, tools, and environment per machine. Works as a direct CLI or an interactive TUI.
Quick Start
Install via cargo
cargo install profilectl
Install via shell script (macOS/Linux)
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/carlosferreyra/profilectl/releases/latest/download/profilectl-installer.sh | sh
Install via PowerShell (Windows)
powershell -ExecutionPolicy ByPass -c "irm https://github.com/carlosferreyra/profilectl/releases/latest/download/profilectl-installer.ps1 | iex"
Usage
Interactive mode (no arguments)
profilectl
Launches a guided TUI to select a profile, preview changes, and apply them.
CLI subcommands
profilectl init [<repo>] [--bundles a,b,c] [--force] [--non-interactive]
profilectl apply [--scope tools|links|all] [--pull] [--force] [--strict]
profilectl publish [<url>]
profilectl status [--scope tools|links|all]
profilectl check [--scope tools|links|all]
profilectl uninstall [--purge]
profilectl scan [--output <path>]
profilectl profile list
profilectl profile show [<name>]
profilectl profile use <name>
Global flags
| Flag | Env | Description |
|---|---|---|
--profile |
PCTL_PROFILE |
Active profile name. Defaults to default. |
--home |
PCTL_HOME |
Path to the dotfiles repo. Defaults to ~/.dotfiles. |
--verbose |
Enable debug-level tracing. | |
--dry-run |
Show what would happen without making changes. |
Selecting a profile
profilectl --profile work apply
Or set the environment variable:
export PCTL_PROFILE=work
profilectl apply
Profiles
Profiles live in profiles/<name>.toml and describe what a machine should look like:
name = "default"
bundles = ["zsh", "git"]
[[links]]
source = "config/zsh/.zshrc"
target = "~/.zshrc"
[[links]]
source = "config/git/.gitconfig"
target = "~/.gitconfig"
[tools]
mise = ["ripgrep", "bat"]
brew = ["eza"]
Profiles support inheritance via extends and pre-built bundles:
name = "work"
extends = "default"
bundles = ["docker", "go"]
[[links]]
source = "config/zsh/.zshrc.work"
target = "~/.zshrc"
[tools]
brew = ["awscli", "terraform"]
The work profile inherits all links and tools from default, then adds or overrides its own.
Merge order: bundles → extends parent → own definition. Own values win on conflict.
Bundles
Nine pre-built bundles are embedded in the binary:
| Bundle | Description |
|---|---|
mise |
Polyglot version & tool manager (replaces nvm, pyenv, asdf) |
uv |
Python tooling (uv, ruff, mypy, pytest) |
rustup |
Full Rust toolchain + nextest, bacon, sccache |
bun |
JavaScript / TypeScript runtime and tooling |
go |
Go toolchain + golangci-lint, air |
docker |
Container runtime (Docker Desktop, docker-compose) |
zsh |
Modern shell stack (zsh, starship, zoxide, fzf, eza) |
git |
Git workflow upgrades (git-lfs, lazygit, delta) |
vscode |
VS Code CLI integrations |
Project Structure
profilectl/
├── bundles/ # Embedded bundle TOML fragments (mise, git, zsh, …)
├── config/ # Source dotfiles (zsh, git, shell) symlinked by profiles
├── profiles/ # Profile TOMLs (default.toml, …)
├── crates/
│ ├── profilectl/ # Binary entry point (thin glue)
│ ├── profilectl-cli/ # Clap subcommands and dispatch
│ ├── profilectl-config/ # Profile schema, loader, global config
│ ├── profilectl-interactive/ # ratatui + crossterm TUI
│ ├── profilectl-types/ # Shared types (Platform, MachineInfo, ProfilectlError)
│ └── profilectl-xtask/ # Dev task runner (cargo xtask check|build|test)
├── scripts/
│ └── release_pypi.py # PyPI thin-wrapper publish script
└── Cargo.toml # Workspace root
See crates/README.md for a description of each crate.
Release Pipeline
Releases are fully automated:
cargo release patch --executeonmain- git-cliff generates
CHANGELOG.md, cargo-release commits and tags - cargo-dist builds binaries for macOS (aarch64 + x86_64), Linux (x86_64), and Windows (x86_64)
- GitHub Release is created with shell/PowerShell installers
- PyPI thin-wrapper package is published via OIDC trusted publishing
Contributing
- Fork the repository
- Create a feature branch from
main(humans: descriptive name; agents:claude/<short-description>) - Open a pull request — CI runs
cargo xtask checkandcargo xtask test
See CONTRIBUTING.md and AGENTS.md for the full workflow.
License
MIT — see LICENSE.
Made with ❤️ by Carlos Ferreyra
Dependencies
~14–30MB
~312K SLoC