Put on your company hat — switch between company environments
Project description
hat — Put On Your Company Hat
A CLI tool for switching between multiple company environments. Manages VPN, SSH keys, cloud credentials, env vars, DNS, git identity, docker registries, browser profiles, tool installation, and git repo cloning.
Install
Requires Python 3.11+ and uv.
# From PyPI
uv tool install hatctl
# Or from GitHub
uv tool install git+https://github.com/apyatkin/personal-tools.git
This installs hat to ~/.local/bin/. Make sure it's in your PATH:
export PATH="$HOME/.local/bin:$PATH"
Setup
Run once after installing:
hat setup
This will:
- Create
~/projects/directory structure - Enable Touch ID for sudo (optional — fingerprint instead of password for VPN, DNS, etc.)
- Generate shell aliases (130+) and completions
- Show next steps
Then add to ~/.zshrc:
eval "$(hat shell-init zsh)"
eval "$(_HAT_COMPLETE=zsh_source hat)"
Update
uv tool install hatctl --upgrade
Uninstall
uv tool uninstall hatctl
Quick Start
# Create a company
hat init acme
# Configure SSH
hat ssh config acme --default-user deploy --default-key acme-sshkey
hat ssh add acme bastion 10.0.1.1
hat ssh add acme web 10.0.1.10 -u root -p 2222
# Configure VPN
hat vpn config acme --provider wireguard
# Store secrets
hat secret set keychain:acme-gitlab-token
hat config add-ssh acme acme-sshkey -f ~/.ssh/acme_ed25519
hat config add-secret acme cloud.nomad.token_ref acme-nomad-token
# Put on your hat
hat on acme
# What hat am I wearing?
hat status
# Switch companies (takes off previous hat first)
hat on globex
# Take off your hat (disconnects VPN too)
hat off
Company Config
Each company lives in ~/Library/hat/companies/<name>/config.yaml. All sections are optional:
name: acme
description: "Acme Corp"
tags: [infra, production]
git:
identity:
name: "Your Name"
email: "you@acme.com"
sources:
- provider: gitlab
host: gitlab.acme.com
group: infrastructure
token_ref: keychain:acme-gitlab-token
- provider: github
org: acme-oss
token_ref: keychain:acme-github-pat
env:
CUSTOM_VAR: value
ssh:
default_user: deploy
default_key_ref: keychain:acme-sshkey
jump_host: bastion.acme.com
jump_user: deploy
keys:
- keychain:acme-sshkey
hosts:
bastion:
address: 10.0.1.1
web:
address: 10.0.1.10
user: root
port: 2222
key_ref: keychain:acme-web-key
vpn:
provider: wireguard # wireguard | amnezia | tailscale
config: ~/projects/acme/wg0.conf
dns:
resolvers: [10.0.0.53]
search_domains: [acme.internal]
hosts:
entries:
- "10.0.1.10 grafana.acme.internal"
cloud:
aws:
profile: acme-prod
sso: true
kubernetes:
kubeconfig: ~/projects/acme/kubeconfig
refresh:
provider: yandex
cluster: acme-k8s
nomad:
addr: https://nomad.acme.com:4646
token_ref: keychain:acme-nomad-token
vault:
addr: https://vault.acme.com:8200
token_ref: keychain:acme-vault-token
consul:
addr: https://consul.acme.com:8500
token_ref: keychain:acme-consul-token
yandex:
profile: acme
digitalocean:
context: acme
hetzner:
token_ref: keychain:acme-hcloud-token
terraform:
vars:
backend_bucket: acme-tf-state
docker:
registries:
- host: registry.acme.com
username_ref: keychain:acme-reg-user
password_ref: keychain:acme-reg-pass
proxy:
http: http://proxy.acme.com:3128
https: http://proxy.acme.com:3128
no_proxy: "*.acme.internal,10.0.0.0/8"
browser:
profile: "Profile 1"
app: google-chrome
apps:
slack:
workspace: acme-corp
jira:
host: acme.atlassian.net
project: INFRA
token_ref: keychain:acme-jira-token
favro:
organization_id: "org-123"
token_ref: keychain:acme-favro-token
SSH Management
hat ssh config acme # show SSH config
hat ssh config acme --default-user deploy # set default user
hat ssh config acme --default-key acme-sshkey # set default key
hat ssh config acme --jump deploy@bastion.com # set jump host
hat ssh add acme bastion 10.0.1.1 # add host
hat ssh add acme db db.internal -u postgres -p 5432 -k acme-db-key
hat ssh list # all hosts, all companies
hat ssh list acme # hosts for one company
hat ssh connect acme bastion # connect (uses defaults)
hat ssh connect acme web -u root # override user
hat ssh remove acme old-server # remove host
SSH keys stored in Keychain are extracted to a temp file (0600) during hat on, loaded via ssh-add, deleted on hat off.
VPN Management
hat vpn config acme --provider wireguard # set provider
hat vpn config acme # show config
hat vpn up acme # connect (prompts)
hat vpn up acme -y # connect (no prompt, Touch ID)
hat vpn down acme # disconnect
hat vpn down acme -y # disconnect (no prompt)
hat vpn status # all companies
hat vpn status acme # one company
VPN config file defaults to ~/projects/<company>/wg0.conf. Supports WireGuard, AmneziaVPN, Tailscale.
hat on connects VPN automatically. hat off disconnects it. Use hat on --no-vpn to skip.
Secrets
Stored in macOS Keychain or Bitwarden. Referenced in config via *_ref fields.
hat secret set keychain:acme-token # paste value, Ctrl-D
hat secret set keychain:acme-key -f key.pem # from file
hat secret get keychain:acme-token # display value
hat secret list # all secrets
hat secret list --company acme # one company
hat secret list --check # verify accessibility
hat secret scan # find + register existing secrets
hat secret delete keychain:old-token # remove
Repo Management
hat repos clone acme # clone all (GitLab subgroups preserved)
hat repos pull acme # pull updates
hat repos pull --all # all companies
hat repos pull --tag infra # companies with tag
hat repos sync acme # clone new + pull existing
hat repos list acme # local vs remote
Repos cloned to ~/projects/<company>/repos/.
Tool Management
Tools defined globally in ~/projects/common/tools.yaml. Three package managers: brew, pipx (uv tool), npm.
hat tools init # generate default tools.yaml
hat tools list # show all with install status
hat tools add brew k9s # add a tool
hat tools add npm @bitwarden/cli # add npm package
hat tools remove brew k9s # remove from list
hat tools install # install/update all
hat tools check # show what's missing
Shell Aliases & Completions
130+ aliases for kubectl, helm, terraform, ansible, nomad, vault, consul, docker, git, and system tools.
hat aliases generate # ~/projects/common/aliases.sh
hat completions generate # ~/projects/common/completions.sh
Sourced automatically by hat shell-init zsh.
Network Tools
hat net domain example.com # WHOIS + RDAP (expiry, registrar)
hat net cert example.com # SSL cert (self-signed, chain, expiry)
hat net ip 8.8.8.8 # geolocation, ISP, hosting
hat net dns example.com # A, AAAA, MX, NS, CNAME, TXT
hat net check host.com # ping + traceroute + ports
hat net check host.com -p 8080 -p 443 # specific ports
Claude Code Skills
13 skills for Claude Code: GitLab, GitHub, Favro, Jira, Kubernetes, Helm, Terraform, Ansible, Nomad, Vault, Consul, Docker, Code Review.
hat skills deploy
What Happens on hat on
Modules activate in order (deactivate in reverse):
- tools — install/update CLI tools
- vpn — connect VPN (skips if already connected)
- dns — configure resolvers
- hosts — add
/etc/hostsentries - ssh — load SSH keys (from Keychain → temp file → ssh-add)
- git — set git identity
- cloud — set cloud credentials (AWS, K8s, Nomad, Vault, etc.)
- env — export custom env vars
- docker — registry login
- proxy — set proxy env vars
- browser — open with company profile
- apps — open Slack, etc.
If a module fails, already-activated modules are rolled back. State tracked in ~/Library/hat/ with atomic writes.
All Commands
hat setup first-time setup
hat on <company> [--no-vpn] put on a company hat
hat off [company] take off (disconnects VPN)
hat status what hat am I wearing?
hat list [--tag TAG] list all hats
hat init <company> scaffold new company
hat ssh config <company> [options] show/set SSH defaults
hat ssh add <company> <name> <addr> [opts] add SSH host
hat ssh list [company] list SSH hosts
hat ssh connect <company> <host> [opts] connect via SSH
hat ssh remove <company> <name> remove SSH host
hat vpn config <company> [options] show/set VPN config
hat vpn up <company> [-y] connect VPN
hat vpn down <company> [-y] disconnect VPN
hat vpn status [company] check VPN status
hat config set <company> <path> <value> set config value
hat config add-ssh <company> <name> [-f] store SSH key
hat config add-secret <company> <path> <name> store secret + ref
hat config validate <company> validate config
hat template <company> --from <other> clone config
hat secret set <ref> [-f FILE] store secret
hat secret get <ref> display secret
hat secret list [--company] [--check] list secrets
hat secret scan find existing secrets
hat secret delete <ref> remove secret
hat repos clone <company> clone all repos
hat repos pull <company> [--all] [--tag] pull updates
hat repos sync <company> clone + pull
hat repos list <company> local vs remote
hat tools init generate tools.yaml
hat tools list show install status
hat tools add <method> <package> add tool
hat tools remove <method> <package> remove tool
hat tools install install/update all
hat tools check show missing
hat tunnel start <company> start SSH tunnels
hat tunnel stop stop tunnels
hat run <company> -- <command> run in company env
hat env <company> [--export] show env vars
hat shell <company> spawn company shell
hat diff <company1> <company2> compare configs
hat net domain <domain> WHOIS + RDAP
hat net cert <host> SSL certificate
hat net ip <address> IP geolocation
hat net dns <domain> DNS records
hat net check <host> [-p PORT] ping + trace + ports
hat doctor [company] health check
hat log [--company] [-n LIMIT] activity log
hat migrate migrate from old path
hat backup [-o DIR] backup configs
hat restore <archive> restore backup
hat kubeconfig merge merge kubeconfigs
hat aliases generate generate aliases
hat completions generate generate completions
hat skills deploy deploy Claude skills
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hatctl-2.3.0.tar.gz.
File metadata
- Download URL: hatctl-2.3.0.tar.gz
- Upload date:
- Size: 122.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5ab6a6e7c8aa4d344c917742f1ff6a4ca249026dc721ec056948354ee9ec2e93
|
|
| MD5 |
1023dd33435d02deb3a814a2062a1ffb
|
|
| BLAKE2b-256 |
21d2746a26450b5caf21e4a5406261d69bdee720cdedec75a48ae8e675a140c1
|
Provenance
The following attestation bundles were made for hatctl-2.3.0.tar.gz:
Publisher:
publish.yml on apyatkin/hatctl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hatctl-2.3.0.tar.gz -
Subject digest:
5ab6a6e7c8aa4d344c917742f1ff6a4ca249026dc721ec056948354ee9ec2e93 - Sigstore transparency entry: 1260858947
- Sigstore integration time:
-
Permalink:
apyatkin/hatctl@43ffe723d25e605a57108fab4e4c5b4a1c252bee -
Branch / Tag:
refs/tags/v2.3.0 - Owner: https://github.com/apyatkin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@43ffe723d25e605a57108fab4e4c5b4a1c252bee -
Trigger Event:
push
-
Statement type:
File details
Details for the file hatctl-2.3.0-py3-none-any.whl.
File metadata
- Download URL: hatctl-2.3.0-py3-none-any.whl
- Upload date:
- Size: 69.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bad790e1873aed9cd4ed5120672c35b9d8f89be48fd069001e811e9b26b52108
|
|
| MD5 |
3865b81b03ab4085c166f10274ab380e
|
|
| BLAKE2b-256 |
eb23f099dddbaf88324713f7aca0b42f1c8adc1bd225e97f0f25e907bbd8f9bf
|
Provenance
The following attestation bundles were made for hatctl-2.3.0-py3-none-any.whl:
Publisher:
publish.yml on apyatkin/hatctl
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hatctl-2.3.0-py3-none-any.whl -
Subject digest:
bad790e1873aed9cd4ed5120672c35b9d8f89be48fd069001e811e9b26b52108 - Sigstore transparency entry: 1260858949
- Sigstore integration time:
-
Permalink:
apyatkin/hatctl@43ffe723d25e605a57108fab4e4c5b4a1c252bee -
Branch / Tag:
refs/tags/v2.3.0 - Owner: https://github.com/apyatkin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@43ffe723d25e605a57108fab4e4c5b4a1c252bee -
Trigger Event:
push
-
Statement type: