Skip to Content
DocumentationDocumentationProvidersProvider Catalog

Provider Catalog

hams ships with 14 builtin providers that cover the bulk of what sits on a typical workstation. Each one wraps a tool you already use and adds auto-record, state tracking, and diff-based apply on top.

The 14 builtin providers

ProviderWrapsPlatformsWhat it manages
HomebrewbrewmacOS, LinuxFormulae and casks via Homebrew
aptapt-getLinux (Debian/Ubuntu)System packages
pnpmpnpmmacOS, LinuxGlobal Node.js packages
npmnpmmacOS, LinuxGlobal Node.js packages
uvuvmacOS, LinuxPython command-line tools
goinstallgo installmacOS, LinuxGo binaries
cargocargo installmacOS, LinuxRust binaries
codecodemacOS, LinuxVS Code extensions
masmasmacOS onlyMac App Store apps
gitgitmacOS, LinuxGlobal git config + repo clones
defaultsdefaultsmacOS onlymacOS system settings
dutidutimacOS onlyDefault app associations for file types
bashbashmacOS, LinuxAny shell script, with a check: for idempotency
AnsibleansiblemacOS, LinuxAnsible playbooks and ad-hoc tasks

Four flavours of resource

Every provider’s resources fit one of four classes. Each class has its own way of figuring out “is this already in the desired state?”

Package — ask the native list command

Providers: Homebrew, apt, pnpm, npm, uv, goinstall, cargo, mas, code

How it probes: Run the native list command (brew list --formula, npm list -g, etc.), check whether the package shows up, grab the version from the output.

- app: ripgrep intro: Fast recursive grep alternative.

KV Config — read it back and compare

Providers: defaults, git (config subcommand), duti

How it probes: Run the corresponding read command (defaults read, git config --get), compare the returned value to the expected one. Match? ok.

- urn: "urn:hams:defaults:finder-show-extensions" step: Show all file extensions in Finder domain: NSGlobalDomain key: AppleShowAllExtensions value: true

Check-based — you write the test

Providers: bash, ansible

How it probes: You supply a check: shell command. Exits 0, it’s done. Exits non-zero, time to run. Idempotency is on you — which means these providers can manage anything you can describe.

- urn: "urn:hams:bash:install-homebrew" step: Install Homebrew run: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" check: command -v brew

Filesystem — does the path exist?

Providers: git (clone subcommand), file

How it probes: Check whether the target path exists. The clone subcommand also confirms the remote URL matches.

- urn: "urn:hams:git-clone:dotfiles" step: Clone dotfiles repository remote: https://github.com/zthxxx/dotfiles.git local_path: ~/Projects/dotfiles default_branch: main

The order providers run in

During hams apply, providers go in the order defined by provider_priority. The default order is deliberate — bash runs before Homebrew, for example, so you can bootstrap Homebrew inside a bash step before the Homebrew provider needs to install anything.

# ~/.config/hams/hams.config.yaml provider_priority: - brew - apt - pnpm - npm - uv - goinstall - cargo - code - mas - git-config - git-clone - defaults - duti - bash - ansible

Names in provider_priority match the internal registry names, which is why git appears here as two entries (git-config + git-clone): the CLI merges them into a single hams git verb, but the apply pipeline still treats them as independent providers with their own state files.

Want a different order? Override it in your store’s hams.config.yaml. Want to run only some of them? Pass hams apply --only=homebrew,pnpm or --except=ansible.

Bringing your own provider

hams supports external providers through hashicorp/go-plugin (local gRPC). The full authoring guide and Go SDK reference live in the Provider API chapter (coming soon).

Last updated on