Full Code of thoughtbot/laptop for AI

main 1d3f29fa6daa cached
11 files
16.0 KB
4.6k tokens
1 requests
Download .txt
Repository: thoughtbot/laptop
Branch: main
Commit: 1d3f29fa6daa
Files: 11
Total size: 16.0 KB

Directory structure:
gitextract_2jgmiphz/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   └── bug_report.md
│   ├── pull_request_template.md
│   └── workflows/
│       ├── dynamic-readme.yml
│       └── dynamic-security.yml
├── .gitignore
├── CHANGELOG
├── CODEOWNERS
├── LICENSE
├── README.md
├── SECURITY.md
└── mac

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---

**Describe the issue**
A clear and concise description of what the problem is.

**Log**
If applicable, please either attach or include the log from the
run of the script that had the problem.

**Please complete the following information:**
 - macOS Version: [e.g. 13.0.1]
 - Fresh install? [Yes/No]

**Additional context**
Add any other context about the problem here.
If the problem beieng reported is not on a fresh macOS install,
please describe what else is already installed.


================================================
FILE: .github/pull_request_template.md
================================================
A description of your change.

- [ ] Updated CHANGELOG
- [ ] Updated README.md (if necessary)


================================================
FILE: .github/workflows/dynamic-readme.yml
================================================
name: update-templates

on: 
  push:
    branches:
      - main
  workflow_dispatch:

jobs:
  update-templates:
    permissions:
      contents: write
      pull-requests: write
      pages: write
    uses: thoughtbot/templates/.github/workflows/dynamic-readme.yaml@main
    secrets:
      token: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .github/workflows/dynamic-security.yml
================================================
name: update-security

on:
  push:
    paths:
      - SECURITY.md
    branches:
      - main
  workflow_dispatch:

jobs:
  update-security:
    permissions:
      contents: write
      pull-requests: write
      pages: write
    uses: thoughtbot/templates/.github/workflows/dynamic-security.yaml@main
    secrets:
      token: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .gitignore
================================================
*.swp
artifacts


================================================
FILE: CHANGELOG
================================================
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [Unreleased]

## 2025-07-09

* Removed deprecated homebrew/services tap

## 2025-06-25

* asdf is now updated if it is already installed and asdf commands were updated
  to work with latest versions.

## 2024-09-24

* Support for macOS Sequoia

## 2023-10-03

### Added

* Support for macOS Sonoma

## 2022-12-02

### Added

* Support for macOS Ventura

### Fixed

* [The warning or failure when installing universal-ctags](https://github.com/thoughtbot/laptop/pull/623)
* [The PostgreSQL Homebrew definition has been fixed](https://github.com/thoughtbot/laptop/pull/612)
* [Return error code for failure sourcing asdf.sh](https://github.com/thoughtbot/laptop/pull/620)
* [Fix for location change of asdf.sh](https://github.com/thoughtbot/laptop/pull/622)

## 2022-03-30

### Changed

* Official support for macOS Monterey on Apple Silicon and Intel and removes official support for prior versions of macOS.
* [Use brew asdk, changes for latest node](https://github.com/thoughtbot/laptop/pull/608)
* [Ignore shellcheck warning SC3043 globally](https://github.com/thoughtbot/laptop/pull/606)
* [Use gpg-suite-no-mail](https://github.com/thoughtbot/laptop/pull/607)
* [Update ctags installation command](https://github.com/thoughtbot/laptop/pull/586)

## 2023-04-24

### Changed

* [Adds Rosetta 2 in case a macbook has M1 architecture](https://github.com/thoughtbot/laptop/pull/628)


================================================
FILE: CODEOWNERS
================================================
# Lines starting with '#' are comments.
# Each line is a file pattern followed by one or more owners.

# More details are here: https://help.github.com/articles/about-codeowners/

# The '*' pattern is global owners.

# Order is important. The last matching pattern has the most precedence.
# The folders are ordered as follows:

# In each subsection folders are ordered first by depth, then alphabetically.
# This should make it easy to add new rules without breaking existing ones.

# Global rule:
*           @cpytel


================================================
FILE: LICENSE
================================================
Copyright (c) 2011-2025 thoughtbot, inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


================================================
FILE: README.md
================================================
Laptop
======

Laptop is a script to set up a macOS laptop for web and mobile development.

It can be run multiple times on the same machine safely.
It installs, upgrades, or skips packages
based on what is already installed on the machine.

Requirements
------------

We support:

* macOS Sequoia (15.x) on Apple Silicon and Intel
* macOS Sonoma (14.x) on Apple Silicon and Intel
* macOS Ventura (13.x) on Apple Silicon and Intel
* macOS Monterey (12.x) on Apple Silicon and Intel

Older versions may work but aren't regularly tested.
Bug reports for older versions are welcome.

Install
-------

Download the script:

```sh
curl --remote-name https://raw.githubusercontent.com/thoughtbot/laptop/main/mac
```

Review the script (avoid running scripts you haven't read!):

```sh
less mac
```

Execute the downloaded script:

```sh
sh mac 2>&1 | tee ~/laptop.log
```

Optionally, review the log:

```sh
less ~/laptop.log
```

Optionally, [install thoughtbot/dotfiles][dotfiles].

[dotfiles]: https://github.com/thoughtbot/dotfiles#install

Debugging
---------

Your last Laptop run will be saved to `~/laptop.log`.
Read through it to see if you can debug the issue yourself.
If not, copy the lines where the script failed into a
[new GitHub Issue](https://github.com/thoughtbot/laptop/issues/new) for us.
Or, attach the whole log file as an attachment.

What it sets up
---------------

macOS tools:

* [Homebrew] for managing operating system libraries.

[Homebrew]: http://brew.sh/

Unix tools:

* [fzf][] for better command history searching
* [Universal Ctags] for indexing files for vim tab completion
* [Git] for version control
* [OpenSSL] for Transport Layer Security (TLS)
* [RCM] for managing company and personal dotfiles
* [The Silver Searcher] for finding things in files
* [Tmux] for saving project state and switching between projects
* [Watchman] for watching for filesystem events
* [Zsh] as your shell

[fzf]: https://github.com/junegunn/fzf
[Universal Ctags]: https://ctags.io/
[Git]: https://git-scm.com/
[OpenSSL]: https://www.openssl.org/
[RCM]: https://github.com/thoughtbot/rcm
[The Silver Searcher]: https://github.com/ggreer/the_silver_searcher
[Tmux]: http://tmux.github.io/
[Watchman]: https://facebook.github.io/watchman/
[Zsh]: http://www.zsh.org/

Heroku tools:

* [Heroku CLI] and [Parity] for interacting with the Heroku API

[Heroku CLI]: https://devcenter.heroku.com/articles/heroku-cli
[Parity]: https://github.com/thoughtbot/parity

GitHub tools:

* [GitHub CLI] for interacting with the GitHub API

[GitHub CLI]: https://cli.github.com/

Image tools:

* [ImageMagick] for cropping and resizing images

Programming languages, package managers, and configuration:

* [asdf-vm] for managing programming language versions
* [Bundler] for managing Ruby libraries
* [Node.js] and [npm], for running apps and installing JavaScript packages
* [Ruby] stable for writing general-purpose code
* [Yarn] for managing JavaScript packages
* [Rosetta 2] for running tools that are not supported in Apple silicon processors

[Bundler]: http://bundler.io/
[ImageMagick]: http://www.imagemagick.org/
[Node.js]: http://nodejs.org/
[npm]: https://www.npmjs.org/
[asdf-vm]: https://github.com/asdf-vm/asdf
[Ruby]: https://www.ruby-lang.org/en/
[Yarn]: https://yarnpkg.com/en/
[Rosetta 2]: https://developer.apple.com/documentation/apple-silicon/about-the-rosetta-translation-environment

Databases:

* [Postgres] for storing relational data
* [Redis] for storing key-value data

[Postgres]: http://www.postgresql.org/
[Redis]: http://redis.io/

It should take less than 15 minutes to install (depends on your machine).

Customize in `~/.laptop.local`
------------------------------

Your `~/.laptop.local` is run at the end of the Laptop script.
Put your customizations there.
For example:

```sh
#!/bin/sh

brew bundle --file=- <<EOF
brew "Caskroom/cask/dockertoolbox"
brew "go"
brew "ngrok"
brew "watch"
EOF

default_docker_machine() {
  docker-machine ls | grep -Fq "default"
}

if ! default_docker_machine; then
  docker-machine create --driver virtualbox default
fi

default_docker_machine_running() {
  default_docker_machine | grep -Fq "Running"
}

if ! default_docker_machine_running; then
  docker-machine start default
fi

fancy_echo "Cleaning up old Homebrew formulae ..."
brew cleanup

if [ -r "$HOME/.rcrc" ]; then
  fancy_echo "Updating dotfiles ..."
  rcup
fi
```

Write your customizations such that they can be run safely more than once.
See the `mac` script for examples.

Laptop functions such as `fancy_echo` and
`gem_install_or_update`
can be used in your `~/.laptop.local`.

See the [wiki](https://github.com/thoughtbot/laptop/wiki)
for more customization examples.

Contributing
------------

Thank you, [contributors]!

[contributors]: https://github.com/thoughtbot/laptop/graphs/contributors

By participating in this project,
you agree to abide by the thoughtbot [code of conduct].

[code of conduct]: https://thoughtbot.com/open-source-code-of-conduct

Edit the `mac` file.
Document in the `README.md` file.
Update the `CHANGELOG`.
Follow shell style guidelines by using [ShellCheck] and [ALE] or deprecated [Syntastic].

```sh
brew install shellcheck
```

[ShellCheck]: http://www.shellcheck.net/about.html
[Syntastic]: https://github.com/scrooloose/syntastic
[ALE]: https://github.com/dense-analysis/ale


### Testing your changes

Test your changes by running the script on a fresh install of macOS.
You can use the free and open source emulator [UTM].

Tip: Make a fresh virtual machine with the installation of macOS completed and
your user created and first launch complete. Then duplicate that machine to test
the script each time on a fresh install that's ready to go.

[UTM]: https://mac.getutm.app

License
-------

Copyright © 2011 thoughtbot, inc.
It is free software,
and may be redistributed under the terms specified in the [LICENSE] file.

[LICENSE]: LICENSE

<!-- START /templates/footer.md -->
## About thoughtbot

![thoughtbot](https://thoughtbot.com/thoughtbot-logo-for-readmes.svg)

This repo is maintained and funded by thoughtbot, inc.
The names and logos for thoughtbot are trademarks of thoughtbot, inc.

We love open source software!
See [our other projects][community].
We are [available for hire][hire].

[community]: https://thoughtbot.com/community?utm_source=github
[hire]: https://thoughtbot.com/hire-us?utm_source=github

<!-- END /templates/footer.md -->


================================================
FILE: SECURITY.md
================================================
<!-- START /templates/security.md -->
# Security Policy

## Supported Versions

Only the the latest version of this project is supported at a given time. If
you find a security issue with an older version, please try updating to the
latest version first.

If for some reason you can't update to the latest version, please let us know
your reasons so that we can have a better understanding of your situation.

## Reporting a Vulnerability

For security inquiries or vulnerability reports, visit
<https://thoughtbot.com/security>.

If you have any suggestions to improve this policy, visit <https://thoughtbot.com/security>.

<!-- END /templates/security.md -->


================================================
FILE: mac
================================================
#!/bin/sh

# Welcome to the thoughtbot laptop script!
# Be prepared to turn your laptop (or desktop, no haters here)
# into an awesome development machine.

# shellcheck disable=SC3043

fancy_echo() {
  local fmt="$1"; shift

  # shellcheck disable=SC2059
  printf "\\n$fmt\\n" "$@"
}

append_to_zshrc() {
  local text="$1" zshrc
  local skip_new_line="${2:-0}"

  if [ -w "$HOME/.zshrc.local" ]; then
    zshrc="$HOME/.zshrc.local"
  else
    zshrc="$HOME/.zshrc"
  fi

  if ! grep -Fqs "$text" "$zshrc"; then
    if [ "$skip_new_line" -eq 1 ]; then
      printf "%s\\n" "$text" >> "$zshrc"
    else
      printf "\\n%s\\n" "$text" >> "$zshrc"
    fi
  fi
}

# shellcheck disable=SC2154
trap 'ret=$?; test $ret -ne 0 && printf "failed\n\n" >&2; exit $ret' EXIT

set -e

if [ ! -d "$HOME/.bin/" ]; then
  mkdir "$HOME/.bin"
fi

if [ ! -f "$HOME/.zshrc" ]; then
  touch "$HOME/.zshrc"
fi

# shellcheck disable=SC2016
append_to_zshrc 'export PATH="$HOME/.bin:$PATH"'

# Determine Homebrew prefix
arch="$(uname -m)"
if [ "$arch" = "arm64" ]; then
  HOMEBREW_PREFIX="/opt/homebrew"
else
  HOMEBREW_PREFIX="/usr/local"
fi

update_shell() {
  local shell_path;
  shell_path="$(command -v zsh)"

  fancy_echo "Changing your shell to zsh ..."
  if ! grep "$shell_path" /etc/shells > /dev/null 2>&1 ; then
    fancy_echo "Adding '$shell_path' to /etc/shells"
    sudo sh -c "echo $shell_path >> /etc/shells"
  fi
  sudo chsh -s "$shell_path" "$USER"
}

case "$SHELL" in
  */zsh)
    if [ "$(command -v zsh)" != "$HOMEBREW_PREFIX/bin/zsh" ] ; then
      update_shell
    fi
    ;;
  *)
    update_shell
    ;;
esac

# checks architecture
if [ "$(uname -m)" = "arm64" ]
  then
  # checks if Rosetta is already installed
  if ! pkgutil --pkg-info=com.apple.pkg.RosettaUpdateAuto > /dev/null 2>&1
  then
    echo "Installing Rosetta"
    # Installs Rosetta2
    softwareupdate --install-rosetta --agree-to-license
  else
    echo "Rosetta is installed"
  fi
fi


gem_install_or_update() {
  if gem list "$1" --installed > /dev/null; then
    gem update "$@"
  else
    gem install "$@"
  fi
}

if ! command -v brew >/dev/null; then
  fancy_echo "Installing Homebrew ..."
    /bin/bash -c \
      "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

    append_to_zshrc "eval \"\$($HOMEBREW_PREFIX/bin/brew shellenv)\""

    export PATH="$HOMEBREW_PREFIX/bin:$PATH"
fi

if brew list | grep -Fq brew-cask; then
  fancy_echo "Uninstalling old Homebrew-Cask ..."
  brew uninstall --force brew-cask
fi

fancy_echo "Updating Homebrew formulae ..."
brew update --force # https://github.com/Homebrew/brew/issues/1151
brew bundle --file=- <<EOF
tap "thoughtbot/formulae"
tap "heroku/brew"

# Unix
brew "universal-ctags"
brew "fzf"
brew "git"
brew "openssl"
brew "rcm"
brew "reattach-to-user-namespace"
brew "the_silver_searcher"
brew "tmux"
brew "vim"
brew "watchman"
brew "zsh"

# Heroku
brew "heroku/brew/heroku"
brew "parity"

# GitHub
brew "gh"

# Image manipulation
brew "imagemagick"

# PDF Rendering
brew "poppler"

# Programming language prerequisites and package managers
brew "libyaml" # should come after openssl
brew "coreutils"
brew "yarn"
cask "gpg-suite-no-mail"

# Databases
brew "postgresql@14", restart_service: :changed
brew "redis", restart_service: :changed
EOF

fancy_echo "Update heroku binary ..."
brew unlink heroku
brew link --force heroku

fancy_echo "Configuring asdf version manager ..."
if [ ! -d "$HOME/.asdf" ]; then
  brew install asdf
  append_to_zshrc "source $(brew --prefix asdf)/libexec/asdf.sh" 1
else
  brew upgrade asdf
fi

alias install_asdf_plugin=add_or_update_asdf_plugin
add_or_update_asdf_plugin() {
  local name="$1"
  local url="$2"

  if ! asdf plugin list | grep -Fq "$name"; then
    asdf plugin add "$name" "$url"
  else
    asdf plugin update "$name"
  fi
}

# shellcheck disable=SC1091
. "$(brew --prefix asdf)/libexec/asdf.sh"
add_or_update_asdf_plugin "ruby" "https://github.com/asdf-vm/asdf-ruby.git"
add_or_update_asdf_plugin "nodejs" "https://github.com/asdf-vm/asdf-nodejs.git"

install_asdf_language() {
  local language="$1"
  local version
  version="$(asdf list all "$language" | grep -v "[a-z]" | tr -s '\n' | tail -1)"

  if ! asdf list "$language" | grep -Fq "$version"; then
    asdf install "$language" "$version"
    asdf set --home "$language" "$version"
  fi
}

fancy_echo "Installing latest Ruby ..."
install_asdf_language "ruby"
gem update --system
number_of_cores=$(sysctl -n hw.ncpu)
bundle config --global jobs $((number_of_cores - 1))

fancy_echo "Installing latest Node ..."
install_asdf_language "nodejs"

if [ -f "$HOME/.laptop.local" ]; then
  fancy_echo "Running your customizations from ~/.laptop.local ..."
  # shellcheck disable=SC1091
  . "$HOME/.laptop.local"
fi
Download .txt
gitextract_2jgmiphz/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   └── bug_report.md
│   ├── pull_request_template.md
│   └── workflows/
│       ├── dynamic-readme.yml
│       └── dynamic-security.yml
├── .gitignore
├── CHANGELOG
├── CODEOWNERS
├── LICENSE
├── README.md
├── SECURITY.md
└── mac
Condensed preview — 11 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (18K chars).
[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 585,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the i"
  },
  {
    "path": ".github/pull_request_template.md",
    "chars": 94,
    "preview": "A description of your change.\n\n- [ ] Updated CHANGELOG\n- [ ] Updated README.md (if necessary)\n"
  },
  {
    "path": ".github/workflows/dynamic-readme.yml",
    "chars": 325,
    "preview": "name: update-templates\n\non: \n  push:\n    branches:\n      - main\n  workflow_dispatch:\n\njobs:\n  update-templates:\n    perm"
  },
  {
    "path": ".github/workflows/dynamic-security.yml",
    "chars": 355,
    "preview": "name: update-security\n\non:\n  push:\n    paths:\n      - SECURITY.md\n    branches:\n      - main\n  workflow_dispatch:\n\njobs:"
  },
  {
    "path": ".gitignore",
    "chars": 16,
    "preview": "*.swp\nartifacts\n"
  },
  {
    "path": "CHANGELOG",
    "chars": 1550,
    "preview": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Change"
  },
  {
    "path": "CODEOWNERS",
    "chars": 519,
    "preview": "# Lines starting with '#' are comments.\n# Each line is a file pattern followed by one or more owners.\n\n# More details ar"
  },
  {
    "path": "LICENSE",
    "chars": 1065,
    "preview": "Copyright (c) 2011-2025 thoughtbot, inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\no"
  },
  {
    "path": "README.md",
    "chars": 6431,
    "preview": "Laptop\n======\n\nLaptop is a script to set up a macOS laptop for web and mobile development.\n\nIt can be run multiple times"
  },
  {
    "path": "SECURITY.md",
    "chars": 661,
    "preview": "<!-- START /templates/security.md -->\n# Security Policy\n\n## Supported Versions\n\nOnly the the latest version of this proj"
  },
  {
    "path": "mac",
    "chars": 4761,
    "preview": "#!/bin/sh\n\n# Welcome to the thoughtbot laptop script!\n# Be prepared to turn your laptop (or desktop, no haters here)\n# i"
  }
]

About this extraction

This page contains the full source code of the thoughtbot/laptop GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 11 files (16.0 KB), approximately 4.6k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!