Skip to content
ithinkihaveacatPublic

About

Shell-related config files and scripts

Topics

Resources

Stars

48 stars

Watchers

2 watching

Forks

Repository files navigation

.dotfiles

Public dotfiles for fish, git, jed, and VS Code — plus a large collection of agent skills and command-line tools for AI-assisted development with agents such as Claude Code, Codex, and Gemini CLI.

Repository layout

.dotfiles/
├── bin/                 # Shell scripts added directly to $PATH
├── fish/
│   ├── config.fish      # Main fish config; loads .private overlay if present
│   ├── conf.d/          # Fish startup snippets
│   ├── completions/     # Fish completions
│   └── functions/       # Fish functions (autoloaded)
├── home/                # Dotfiles symlinked into $HOME by install.sh
├── etc/                 # Tool-specific config (git templates, VS Code, etc.)
├── skills/              # Agent skills (see Agent skills below)
├── config/              # Plugins for the skill and permission tools
├── docker/              # Dockerfile + notes for building an image from this repo
├── tests/               # TAP tests for bin/ scripts
└── install.sh           # Idempotent install/update script

install.sh symlinks home/.* into $HOME, installs packages, and wires up tool-specific config. It is safe to run multiple times, and doubles as the updater: an existing checkout is fast-forwarded before applying. It can be run locally (./install.sh) or piped straight from the network (see Installation).

Agent skills

The skills/ directory contains Agent Skills: folders with a SKILL.md (metadata and instructions) plus supporting scripts and references that teach AI coding agents how to perform specific tasks — driving Android devices over adb, inspecting APKs, managing emulators, looking up current AndroidX library facts, enforcing coding standards, planning award flights, and more.

Key skills

Skill Description
adb ADB device automation with a Wear OS focus: screenshots, screen recording, tiles, dumpsys, logcat
agent-tools CLI tools delegating analysis to AI models: image description, screenshot diffing, deep research
apk Offline APK binary analysis: manifests, resources, launcher icons, split APKs
coding-standards This repo's coding standards: shell/Python/Markdown formatting, CLI design, commit message style
emumanager (Deprecated — prefer android-cli) Legacy Android SDK bootstrap and AVD/emulator manager
jetpack Current AndroidX/Jetpack facts that are wrong from memory: versions, Maven coordinates, dependencies

More specialised skills: android-testing (system state and connectivity testing on phone and Wear OS), wear-widget (reverse-engineering widgets), and workspace-tools (skill selection and agent tool permissions). Personal-workflow skills live here too: agent-review, taskgo, technical-writing, and travel.

Installing skills into a workspace

Skills are intentionally not installed globally — every project seeing every skill would be noise. Instead, the bundled skill command manages them per workspace as untracked symlinks in .claude/skills/ or .agents/skills/, auto-detecting which agent is installed:

skill add --defaults # link the default skills
skill add jetpack    # add one skill by name
skill list           # what's linked here, 'default' or 'added'

Skill names resolve against skills/ in this repo and its .private/.corp overlays (later layers shadow by name); plugins in config/skill/plugins/ register additional remote skills from third-party catalogs. The default skills are set by etc/skill/defaults.sh in each layer, which install.sh runs. A fresh clone links them into the repository, and the agent wrappers link them into each session.

Overlays

SECURITY NOTE: The .dotfiles repository is public. To prevent the leakage of sensitive information (such as API keys, corporate tool configurations, or internal pathnames), two private companion repositories can optionally be cloned: ~/.private and ~/.corp.

This architecture is specifically designed to help both humans and AI agents understand what goes where and ensures private information remains strictly out of the public repository. This repository works fine without them.

Purpose of each layer

Repo Intended for
~/.dotfiles Public config, tools, and scripts
~/.private Personal secrets, API keys, private tooling
~/.corp Work machine config, internal tooling

Precedence

install.sh processes overlays in this order: .dotfiles → .private → .corp. Later layers win on conflict. A file in ~/.corp always beats the same path in ~/.private or ~/.dotfiles.

How files are applied

Two functions handle overlay merging, with different semantics:

  • link_overlay_path rel dst — symlinks dst to the single highest-priority source that provides rel. Used for whole-file configs where only one version makes sense (e.g. etc/starship/starship.toml).

  • link_overlay_files rel dst — iterates every overlay in order and symlinks each file it finds under rel/ into dst/. All overlays contribute; later layers win on filename collision. Used when multiple overlays may each add files to a directory (e.g. etc/code/).

home/ dotfiles are linked by iterating all overlays in order with ln -sf, so the last overlay to provide a given filename wins.

Overlay-aware paths

Path Mechanism Notes
home/.* link_home_dotfiles (all overlays) Last overlay wins per filename
etc/agents/AGENTS.md overlay_path (highest wins) Symlinked to ~/.codex/, ~/.gemini/, ~/.claude/ (gated on their respective binaries)
etc/agents/agy/hooks.json link_overlay_path Symlinked to ~/.gemini/config/hooks.json (gated on agy)
etc/agents/agy/hooks link_overlay_path Symlinked to ~/.gemini/config/hooks (gated on agy)
etc/shpool/config.toml link_overlay_path
etc/starship/starship.toml link_overlay_path
etc/ghostty/config link_overlay_path
etc/bat/config link_overlay_path
etc/code/ link_overlay_files VS Code settings.json, keybindings.json, etc.
etc/macos/KeyBindings overlay_path rsync'd (not symlinked) due to macOS bug
etc/macos/Solarized.clr overlay_path Copied to ~/Library/Colors/
etc/skill/defaults.sh run by install.sh Adds or removes default skills with skill --scope defaults
skills/*/ skill catalog source Not linked globally; added per workspace via skill add (see Agent skills)

Per-overlay update hooks

After the main install, install.sh runs ~/.private/update and ~/.corp/update if they exist and are executable. These hooks handle overlay-specific setup that cannot be expressed as file overlays (package installs, auth setup, etc.).

Expected layout

.private/               # same structure for .corp
├── fish/
│   ├── conf.d/         # Startup snippets sourced by config.fish
│   ├── completions/    # Completions prepended to fish_complete_path
│   ├── functions/      # Functions prepended to fish_function_path
│   └── secrets.fish    # API keys and tokens (chmod 600)
├── home/               # Dotfiles symlinked into $HOME (e.g. .gitconfig.local)
├── etc/                # Tool-specific config (see overlay-aware paths above)
├── skills/             # Agent skills that shadow ~/.dotfiles/skills/ by name
└── update              # Optional hook run at end of ./install.sh

fish/config.fish prepends ~/.private/fish/functions (and .corp equivalents) and ~/.private/fish/completions to the fish search paths, and sources any ~/.private/fish/conf.d/*.fish snippets at shell startup.

To install: clone your private repos to ~/.private and/or ~/.corp, then run ./install.sh again.

Secret management

Secrets (API keys, tokens) live in ~/.private/fish/secrets.fish and are not sourced in full at shell startup. Three fish functions provide on-demand access:

Function Usage Description
setsecret setsecret NAME [NAME...] Load secret(s) into the current shell
getsecret getsecret NAME Print secret value(s) to stdout (array-safe)
envsecret envsecret NAME [...] [--] CMD Run a command with secret(s) injected

envsecret is the safest option for scripts: secrets are injected into the child process and never leak into the calling shell.

A ~/.private/fish/conf.d/ snippet uses setsecret --if-unset to auto-load a small set of everyday secrets at shell startup.

Run setsecret --help, getsecret --help, or envsecret --help for details.

Environment management

direnv handles per-project environment switching, configured via ~/.direnvrc (symlinked from home/.direnvrc). To activate it in a project, create an .envrc file in the project root.

Node.js, Ruby, and Python versions are selected per directory with envrc blocks and installed with node-install, ruby-install, and python-install:

node-install 22        # latest 22.x into ~/.local/share/node/versions
envrc create node 22   # use node 22 + layout node (node_modules/.bin on PATH)

ruby-install 3.4       # compiles latest 3.4.x into ~/.local/share/ruby/versions
envrc create ruby 3.4  # use ruby 3.4 + layout ruby (gems in .direnv/ruby)

python-install         # checks that uv is installed
envrc create uv        # layout uv (creates and activates .venv)

Ruby builds need the ruby-build toolchain and its build dependencies, which install with install.sh --with ruby. The installers live in the workspace-tools skill; its Runtime Versions section covers the full workflow, including diagnosing a project that runs on the wrong version.

Installation

The same install.sh script both installs and updates, and runs in two ways. git must already be installed either way (see Prerequisites).

Option 1: Straight from the network

Clones the repo to ~/.dotfiles (if absent), points the push remote at SSH, then installs — and on later runs, updates (it fast-forwards ~/.dotfiles before applying):

curl -fsSL https://raw.githubusercontent.com/ithinkihaveacat/dotfiles/main/install.sh | bash

It must be piped to bash, not sh — the script is bash and refuses to run under other shells. Pass flags after -s --, e.g. … | bash -s -- --force. To download the whole script before running anything (rather than streaming it into the interpreter), use the equivalent:

bash -c "$(curl -fsSL https://raw.githubusercontent.com/ithinkihaveacat/dotfiles/main/install.sh)"

Option 2: From a local checkout

cd $HOME
git clone https://github.com/ithinkihaveacat/dotfiles.git .dotfiles
cd .dotfiles
git remote set-url origin --push git@github.com:ithinkihaveacat/dotfiles.git
./install.sh

After cloning ~/.private and/or ~/.corp (if available), run ./install.sh again so the overlay is applied.

Note: install.sh may overwrite unmanaged files in locations such as ~/Library/KeyBindings. It is otherwise safe to run multiple times.

Choosing what runs

install.sh is split into features (linking dotfiles, packages, uv, agent setup, and so on), and a profile picks which of them run. The default, workstation, sets up a long-lived machine for interactive use: dotfiles, fish and its completions, core packages and interactive extras, and a daily upgrade of everything installed. Heavier package sets (android, ruby, media, services) are in no profile and are added with --with:

./install.sh --with android,ruby  # also install Android and Ruby tooling
./install.sh --without upgrades   # skip the daily upgrades
./install.sh --prune              # also remove brew packages no feature installs

--only names the features outright, and -n/--dry-run prints the selection without running anything; ./install.sh --help lists the features and profiles. Once installed, a package is kept current by later runs whether or not its feature is selected again.

A failing feature is reported and the rest still run; the exit status is non-zero if any failed. Set AGENT_OFFLINE=1 to skip every feature that needs the network.

Cloud environments

For the setup script of a disposable cloud or agent container, use the cloud profile:

curl -fsSL https://raw.githubusercontent.com/ithinkihaveacat/dotfiles/main/install.sh | bash -s -- --profile cloud

It links the dotfiles and fish config, prefetches what the uv-based scripts need, and sets up skill plugins and default skills. It does not use sudo, install or upgrade packages, update uv or agent CLIs, pull the repositories, or change npm's prefix, so it needs no access beyond GitHub and uv's package index. The platform's own agent setup is left alone.

Prerequisites

git

  • Ubuntu/Debian: sudo apt-get install git
  • macOS: xcode-select --install

Platform-specific setup

macOS

Raspberry Pi

Complete setup sequence for a fresh Raspberry Pi OS install.

  1. Use the Raspberry Pi Imager to write the OS to an SD card or SSD.

    • For a headless install: Raspberry Pi OS (other) > Raspberry Pi OS Lite.
    • In OS customisation: enable SSH (Remote access section).
    • (Optional) Configure Wi-Fi.
  2. SSH in: ssh mjs@lil.local (substitute your username and hostname).

    • (Optional) If using Ghostty, copy the terminfo from your local machine: infocmp -x xterm-ghostty | ssh mjs@lil.local -- tic -x -
  3. Update the OS:

    sudo apt-get update && sudo apt-get upgrade -y

    Reboot if /var/run/reboot-required exists: sudo reboot

  4. Install git: sudo apt-get install git

  5. Install Tailscale: curl -fsSL https://tailscale.com/install.sh | sh then sudo tailscale up

  6. (Optional) Install Node.js and npm: sudo apt-get install nodejs npm (for newer versions see Node.js).

  7. (Optional) Disable WiFi and Bluetooth: add these lines under [all] in /boot/firmware/config.txt:

    dtoverlay=disable-wifi
    dtoverlay=disable-bt
    
  8. (Optional) Change hostname: edit /etc/hostname and /etc/hosts.

  9. Reboot after any optional steps above: sudo reboot

Once complete, proceed to Installation.

Tip: Use VS Code's Remote - SSH extension to edit files on the Pi.

Local binaries

Put manually installed binaries in ~/.local/bin.

Testing and CI

Scripts are tested with TAP-format tests run via prove. Tests are co-located with the code they cover: tests/test-* for bin/ scripts and skills/*/tests/test-* for skill scripts. Run them with:

prove -j 9 tests/test-* skills/*/tests/test-*

See tests/README.md for details, including how to run tests offline and in isolated environments.

A GitHub Actions workflow (.github/workflows/lint.yml) runs on every push: shellcheck and shfmt via skills/coding-standards/scripts/shell-format over all Bash scripts (bin/, skills/*/scripts/, install.sh), ruff via skills/coding-standards/scripts/python-format over all Python scripts, plus the full test suite.

Offline environments

Tools managed by uv, meaning scripts with a uv run --script shebang and the formatters that run pinned tools via uvx (ruff, shfmt, shellcheck), download their dependencies on first use. To prepare a CI job or cloud agent environment that will later lose network access, run this once while online, e.g. from the environment's setup script:

./install.sh --only uv               # install uv; fetch everything into uv's cache
UV_OFFLINE=1 ./install.sh --only uv  # check, without the network, that nothing is missing

The check downloads nothing and puts nothing on PATH, but it is not read-only: it builds each script's environment inside uv's cache from the packages already there, which is how it proves they work offline.

--only uv runs just the uv feature of install.sh: no git pull, no symlinks into $HOME, no sudo, and no other packages.

Afterwards, run with UV_OFFLINE=1 and AGENT_OFFLINE=1 (see tests/README.md). CI does exactly this before running the tests. Dependencies installed outside uv (e.g. fish, xmllint, java) are not covered.

Author

mjs@beebo.org

About

Shell-related config files and scripts

Topics

Resources

Stars

48 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages