Skip to content

codoworks/devstrap

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Devstrap

A modern, OS-agnostic CLI tool for automating developer machine setup using YAML-based configuration.

Features

  • Cross-platform: Works on macOS and Linux (Ubuntu, Arch, Fedora)
  • Declarative configuration: Define your environment in YAML files
  • Idempotent: Safe to run multiple times - skips what's already done
  • Dotfile templating: Use Go templates with OS-specific conditionals
  • System settings: Configure macOS defaults and GNOME gsettings
  • Multiple package managers: Homebrew, APT, Pacman, DNF
  • Dry-run mode: Preview changes before applying

Installation

One-liner (recommended)

curl -fsSL https://raw.githubusercontent.com/codoworks/devstrap/main/install.sh | bash

Go Install

go install github.com/codoworks/devstrap@latest

Build from Source

git clone https://github.com/codoworks/devstrap.git
cd devstrap
go build -o devstrap .

Quick Start

# 1. Initialize configuration
devstrap init

# 2. Edit your config files
vim ~/.config/devstrap/tools.yaml

# 3. Preview what will happen
devstrap apply --dry-run

# 4. Apply configuration
devstrap apply

Commands

devstrap init

Initialize a new configuration directory with sample files.

devstrap init                      # Create config in ~/.config/devstrap
devstrap init --path ~/dotfiles    # Create config in custom location
devstrap init --force              # Overwrite existing configuration

Flags:

Flag Short Description
--path -p Path to create config (default: ~/.config/devstrap)
--force -f Overwrite existing configuration

devstrap apply

Apply configuration to set up your development environment.

devstrap apply                     # Apply from default location
devstrap apply --dry-run           # Preview changes without executing
devstrap apply --verbose           # Show detailed output
devstrap apply --config ~/dotfiles # Use custom config location

Flags:

Flag Short Description
--config -c Path to config file or directory (default: ~/.config/devstrap)
--dry-run -n Show what would be done without making changes
--verbose -v Show detailed output

devstrap status

Show what's installed vs what's configured.

devstrap status                    # Check status from default config
devstrap status --config ~/dotfiles

Flags:

Flag Short Description
--config -c Path to config file or directory

devstrap os

Display detected system information and available package managers.

devstrap os

Example output:

System Information
──────────────────
OS:              macOS
Architecture:    arm64
Hostname:        macbook
Home:            /Users/dexter
Shell:           /bin/zsh
Config:          /Users/dexter/.config/devstrap

Package Managers
──────────────────
brew (primary)

Configuration

Devstrap uses YAML configuration files. By default, these live in ~/.config/devstrap/.

File Structure

~/.config/devstrap/
├── devstrap.yaml       # Main config (includes other files)
├── tools.yaml          # Tools to install
├── directories.yaml    # Directories to create
├── profiles.yaml       # Dotfiles to manage
├── configs.yaml        # System settings (macOS defaults, gsettings)
└── dotfiles/           # Dotfile templates
    ├── .gitconfig.tmpl
    └── .aliases

Main Config (devstrap.yaml)

version: "1"

include:
  - tools.yaml
  - directories.yaml
  - profiles.yaml
  - configs.yaml

vars:
  git_name: "Your Name"
  git_email: "you@example.com"
  editor: "vim"

Tools (tools.yaml)

tools:
  # Simple - uses native package manager
  - name: git

  - name: curl

  - name: jq

  # Specify which package manager to use
  - name: go
    platform: brew
    package:
      brew: golang
      apt: golang-go
      pacman: go

  # With OS-specific package names
  - name: fd
    package:
      macos: fd
      ubuntu: fd-find
      arch: fd

  # Platform with sub-tools (e.g., Node.js with npm packages)
  - name: node
    method: script
    script: |
      export NVM_DIR="$HOME/.nvm"
      [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
      nvm install 20
    check: "node --version"
    tools:
      - name: typescript
        install: "npm install -g typescript"
        check: "tsc --version"
      - name: yarn
        install: "npm install -g yarn"
        check: "yarn --version"

  # macOS cask application
  - name: visual-studio-code
    method: cask
    when:
      os: [macos]

  # Homebrew tap
  - name: heroku
    platform: brew
    method: tap
    options:
      tap: heroku/brew

  # Custom script installation
  - name: nvm
    method: script
    script: |
      curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
    check: "[ -d ~/.nvm ]"

Tool fields:

Field Description
name Package name (required)
platform Package manager to use: brew, apt, pacman, dnf
package OS/platform-specific package name overrides
method Install method: native, cask, tap, script
options Platform-specific options (e.g., tap: heroku/brew for brew taps)
script Custom install script (for method: script)
check Command to verify installation
post_install Commands to run after installation
when.os Only install on specified OS: macos, ubuntu, arch, fedora, linux
tools Sub-tools that depend on this tool (see below)

Sub-tool fields:

Field Description
name Sub-tool name (required)
install Installation command (required)
check Command to verify installation (optional)

Sub-tools are displayed indented under their parent tool in devstrap status:

Tools:
  [+] node
      [+] typescript
      [+] yarn
      [-] eslint

Directories (directories.yaml)

directories:
  - path: ~/Developer
    env: DEV_HOME

  - path: ~/bin
    add_to_path: true

  - path: ~/Developer/projects

  - path: ~/.local/share

Directory fields:

Field Description
path Directory path (required, supports ~)
env Environment variable to set to this path
add_to_path Add directory to PATH

Profiles (profiles.yaml)

profiles:
  # Template with variable substitution
  - name: gitconfig
    source: ~/.config/devstrap/dotfiles/.gitconfig.tmpl
    target: ~/.gitconfig
    action: template

  # Symlink (changes to source reflect immediately)
  - name: aliases
    source: ~/.config/devstrap/dotfiles/.aliases
    target: ~/.aliases
    action: symlink

  # Copy (one-time copy)
  - name: ssh-config
    source: ~/.config/devstrap/dotfiles/ssh-config
    target: ~/.ssh/config
    action: copy

Profile actions:

Action Description
symlink Create symbolic link to source
copy Copy source to target
template Process as Go template, then copy

System Configs (configs.yaml)

Manage OS-level settings like macOS defaults and GNOME gsettings.

configs:
  # macOS Dock settings
  - name: dock-autohide
    domain: com.apple.dock
    key: autohide
    value: true
    type: bool
    restart: ["killall Dock"]
    when:
      os: [macos]
    description: "Enable Dock auto-hide"

  # macOS keyboard settings
  - name: key-repeat-rate
    domain: NSGlobalDomain
    key: KeyRepeat
    value: 2
    type: int
    when:
      os: [macos]
    description: "Fast key repeat"

  # GNOME desktop settings (Linux)
  - name: gnome-dark-mode
    backend: gsettings
    domain: org.gnome.desktop.interface
    key: color-scheme
    value: "'prefer-dark'"
    when:
      os: [linux]
    description: "Enable GNOME dark mode"

Config fields:

Field Description
name Display name for the setting (required)
backend Config backend: macosDefaults, gsettings (auto-detected if empty)
domain Domain/schema (e.g., com.apple.dock, org.gnome.desktop.interface)
key Configuration key (e.g., autohide, color-scheme)
value Value to set (bool, int, float, string)
type Value type: bool, int, float, string (inferred if empty)
restart Commands to run after setting (e.g., ["killall Dock"])
when.os Only apply on specified OS: macos, linux
description Human-readable description

Templating

Dotfiles with action: template support Go's text/template syntax.

Built-in Variables

Variable Description
.OS Operating system: macos, linux
.Arch Architecture: amd64, arm64
.Home Home directory path
.Username Current username
.Hostname Machine hostname

Plus all variables defined in vars: section of your config.

Template Functions

String functions: lower, upper, title, trimSpace, replace, contains, hasPrefix, hasSuffix, split, join

Path functions: joinPath, dirName, baseName, extName, cleanPath

Environment: env, envOr, expandEnv

Conditionals: default, coalesce, isSet

Example Template

# ~/.config/devstrap/dotfiles/.gitconfig.tmpl

[user]
    name = {{.git_name}}
    email = {{.git_email}}

[core]
    editor = {{.editor}}
{{- if eq .OS "macos"}}
    ignorecase = false

[credential]
    helper = osxkeychain
{{- end}}

[alias]
    co = checkout
    br = branch
    st = status
    lg = log --oneline --graph

Complete Example

Here's a full configuration for a typical development setup:

devstrap.yaml:

version: "1"

include:
  - tools.yaml
  - directories.yaml
  - profiles.yaml
  - configs.yaml

vars:
  git_name: "Jane Developer"
  git_email: "jane@example.com"
  editor: "code --wait"
  github_user: "janedev"

tools.yaml:

tools:
  # Essentials
  - name: git
  - name: curl
  - name: wget
  - name: jq
  - name: ripgrep
  - name: fd
    package:
      ubuntu: fd-find
  - name: fzf
  - name: tmux
  - name: neovim
    package:
      macos: neovim
      ubuntu: neovim
      arch: neovim
      fedora: neovim

  # Development
  - name: go
    post_install:
      - go install golang.org/x/tools/gopls@latest

  - name: node
    check: "node --version"

  # macOS apps
  - name: iterm2
    method: cask
    when:
      os: [macos]

  - name: docker
    method: cask
    when:
      os: [macos]

directories.yaml:

directories:
  - path: ~/Developer
  - path: ~/Developer/personal
  - path: ~/Developer/work
  - path: ~/bin
    add_to_path: true

profiles.yaml:

profiles:
  - name: gitconfig
    source: ~/.config/devstrap/dotfiles/.gitconfig.tmpl
    target: ~/.gitconfig
    action: template

  - name: zshrc
    source: ~/.config/devstrap/dotfiles/.zshrc
    target: ~/.zshrc
    action: symlink

  - name: tmux
    source: ~/.config/devstrap/dotfiles/.tmux.conf
    target: ~/.tmux.conf
    action: symlink

configs.yaml:

configs:
  - name: dock-autohide
    domain: com.apple.dock
    key: autohide
    value: true
    restart: ["killall Dock"]
    when:
      os: [macos]

  - name: finder-show-extensions
    domain: NSGlobalDomain
    key: AppleShowAllExtensions
    value: true
    restart: ["killall Finder"]
    when:
      os: [macos]

Supported Package Managers

Package Manager Platforms Notes
Homebrew macOS, Linux Also supports casks on macOS
APT Debian, Ubuntu
Pacman Arch Linux
DNF Fedora, RHEL

License

MIT License - See LICENSE for details.

About

Developer Machine Boostrap

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published