Put on your company hat — switch between company environments
Project description
hat — Put On Your Company Hat
Version 2.0.0
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
# From PyPI
uv tool install hatctl
# Or from GitHub
uv tool install git+https://github.com/apyatkin/personal-tools.git
Update
uv tool install hatctl --upgrade
# Or from GitHub
uv tool install git+https://github.com/apyatkin/personal-tools.git --force
Uninstall
uv tool uninstall hatctl
Shell Integration
Add to ~/.zshrc:
eval "$(hat shell-init zsh)"
This sources env vars, aliases, and completions on every prompt and adds a [company] indicator.
Quick Start
# Create a company config
hat init acme
# Or configure without editing YAML
hat config set acme git.identity.name "Your Name"
hat config set acme git.identity.email "you@acme.com"
hat config set acme cloud.nomad.addr "https://nomad.acme.com:4646"
hat config add-ssh acme ~/.ssh/acme_ed25519
hat config add-secret acme cloud.nomad.token_ref acme-nomad-token
# Put on your Acme hat
hat on acme
# What hat am I wearing?
hat status
# Switch to another company (takes off previous hat first)
hat on globex
# Take off your hat
hat off
Company Config
Each company lives in ~/Library/hat/companies/<name>/config.yaml. All sections are optional — only configure what you need:
name: acme
description: "Acme Corp"
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:
keys:
- ~/.ssh/acme_ed25519
config: ~/Library/hat/companies/acme/ssh_config
vpn:
provider: wireguard # wireguard | amnezia | tailscale
config: ~/Library/hat/companies/acme/wg0.conf
interface: wg-acme
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: ~/Library/hat/companies/acme/kubeconfig
refresh:
provider: yandex # yandex | aws | digitalocean
cluster: acme-k8s
nomad:
addr: https://nomad.acme.internal: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: "Acme"
app: google-chrome # google-chrome | firefox | arc
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
Config Without Editing YAML
# Set any config value
hat config set <company> <path> <value>
# Add SSH key (stored in Keychain, never on disk)
hat config add-ssh <company> <keychain-name> -f ~/.ssh/key
hat config add-ssh <company> <keychain-name> # paste key, Ctrl-D
# Store secret in Keychain + add ref to config
hat config add-secret <company> <config-path> <keychain-name>
hat config add-secret <company> <config-path> <keychain-name> -f <file>
SSH keys stored in Keychain are extracted to a temporary file (0600 permissions) during hat on, loaded via ssh-add, and deleted on hat off. Keys never persist on disk.
Secrets
Secrets are referenced in config via *_ref fields and resolved at activation time from:
- macOS Keychain:
keychain:<service-name> - Bitwarden:
bitwarden:<item>,bitwarden:<item>/password,bitwarden:<item>/field/<name>
Values are base64-encoded in Keychain to support multiline secrets (SSH keys, certs).
# Store a secret (paste multiline, Ctrl-D to finish)
hat secret set keychain:acme-gitlab-token
# Store from file (SSH keys, certs)
hat secret set keychain:acme-sshkey -f ~/.ssh/acme_ed25519
# Display a secret
hat secret get keychain:acme-gitlab-token
Repo Management
Clone all repos from a company's GitLab groups and GitHub orgs:
# Clone all repos (preserves GitLab subgroup structure)
hat repos clone acme
# Pull updates for all repos
hat repos pull acme
# Pull all companies
hat repos pull --all
# Show what's cloned vs missing
hat repos list acme
Repos are cloned to ~/projects/<company>/repos/.
Tool Management
Tools are defined globally in ~/projects/common/tools.yaml (not per-company). They're automatically checked on each hat on. Missing tools are installed, outdated tools are upgraded. Update checks are throttled to once per 24 hours.
# Generate default tools.yaml
hat tools init
# Edit to customize
$EDITOR ~/projects/common/tools.yaml
# Check tools without switching context
hat tools check
brewtools: installed via Homebrewpipxtools: installed viauv tool(isolated Python venvs)
Shell Aliases & Completions
Generate global aliases and completions for all DevOps tools:
hat aliases generate # ~/projects/common/aliases.sh
hat completions generate # ~/projects/common/completions.sh
These are sourced automatically by hat shell-init zsh. Includes aliases like k for kubectl, tf for tofu, dc for docker compose, and completions for all tools.
Claude Code Skills
12 DevOps skills for Claude Code are included in skills/. Deploy them to make them available across all company repos:
# Set skills source in global config
mkdir -p ~/Library/hat
echo "skills_source: /path/to/personal-tools/skills" > ~/Library/hat/config.yaml
# Deploy skills as symlinks
hat skills deploy
Skills cover: GitLab, GitHub, Favro, Jira, Kubernetes, Helm, Terraform, Ansible, Nomad, Vault, Consul, Docker.
What Happens on hat on
Modules activate in this order (deactivate in reverse):
- tools — install/update required CLI tools
- vpn — connect VPN (prompts before
sudo) - dns — configure resolvers (prompts before
sudo) - hosts — add
/etc/hostsentries (prompts beforesudo) - ssh — load SSH keys into agent
- git — set git identity via env vars
- cloud — set cloud credentials, run login commands
- env — export custom env vars
- docker — log into registries
- proxy — set proxy env vars
- browser — open browser with company profile
- apps — open Slack, etc.
State is tracked in ~/Library/hat/state.json so hat off and hat status work across shell restarts.
Network Tools
hat net domain example.com # WHOIS/RDAP lookup
hat net cert example.com # SSL certificate info
hat net ip 1.2.3.4 # IP geolocation + ISP
hat net dns example.com # A, AAAA, MX, NS, CNAME, TXT records
hat net check host.com # ping + traceroute + port check
hat net check host.com -p 8080 # check specific ports
All Commands
hat on <company> put on a company hat
hat off take off your hat
hat status what hat am I wearing?
hat list [--tag TAG] list all hats
hat init <company> scaffold new company config
hat config set <company> <path> <value> set a config value
hat config add-ssh <company> <name> [-f] store SSH key + add to config
hat config add-secret <company> <path> <name> store secret + add ref
hat config add-host <company> <name> <addr> [-u USER] [-k KEY]
hat config validate <company> validate config
hat template <company> --from <other> clone company config
hat ssh <company> <host> [-u USER] SSH via jump host (named or raw)
hat tunnel start <company> start SSH tunnels
hat tunnel stop stop tunnels
hat repos clone <company> clone all repos
hat repos pull <company> [--tag TAG] pull updates
hat repos pull --all pull all companies
hat repos sync <company> clone + pull in one
hat repos list <company> list local vs remote
hat run <company> -- <command> run command in company env
hat env <company> [--export] show env vars (dry run)
hat shell <company> spawn shell with company env
hat diff <company1> <company2> compare configs
hat secret set <ref> [-f FILE] store a secret
hat secret get <ref> display a secret
hat doctor [<company>] health check
hat log [--company NAME] [-n LIMIT] activity log
hat migrate migrate from ~/.config/ctx/
hat backup [-o DIR] backup configs
hat restore <archive> restore from backup
hat tools init generate tools.yaml
hat tools check check/install tools
hat net domain <domain> WHOIS info
hat net cert <host> SSL certificate info
hat net ip <address> IP geolocation
hat net dns <domain> DNS records
hat net check <host> [-p PORT] ping + traceroute + ports
hat kubeconfig merge merge all kubeconfigs
hat aliases generate generate aliases.sh
hat completions generate generate completions.sh
hat completion zsh shell completion code
hat skills deploy deploy Claude Code skills
hat shell-init zsh output shell integration
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.0.0.tar.gz.
File metadata
- Download URL: hatctl-2.0.0.tar.gz
- Upload date:
- Size: 94.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e02d2aec0182b9015d415f2dcdbf7b0f8d1c3fd54af700d60dff220cfc5c9e8e
|
|
| MD5 |
655b8b0b9acfd53caa594ceb0e724351
|
|
| BLAKE2b-256 |
7d620975d261432d5ddfd20a9269ee1ab93f296a29585dc794cb477526b0db3e
|
Provenance
The following attestation bundles were made for hatctl-2.0.0.tar.gz:
Publisher:
publish.yml on apyatkin/personal-tools
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hatctl-2.0.0.tar.gz -
Subject digest:
e02d2aec0182b9015d415f2dcdbf7b0f8d1c3fd54af700d60dff220cfc5c9e8e - Sigstore transparency entry: 1243626270
- Sigstore integration time:
-
Permalink:
apyatkin/personal-tools@86216a889da7dbf5da5c3a62973369153767c2ed -
Branch / Tag:
refs/tags/v2.0.0 - Owner: https://github.com/apyatkin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@86216a889da7dbf5da5c3a62973369153767c2ed -
Trigger Event:
push
-
Statement type:
File details
Details for the file hatctl-2.0.0-py3-none-any.whl.
File metadata
- Download URL: hatctl-2.0.0-py3-none-any.whl
- Upload date:
- Size: 43.9 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 |
c420c12457f57ea485dd38a768dc71cba1aec947800251d6cc203c663e1499d7
|
|
| MD5 |
76388620ba926e3380576f3de76a7945
|
|
| BLAKE2b-256 |
5d9b892f0dc9a6f484bda8e798d7949dc94c1f2c00207d8e029c4453839473b0
|
Provenance
The following attestation bundles were made for hatctl-2.0.0-py3-none-any.whl:
Publisher:
publish.yml on apyatkin/personal-tools
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hatctl-2.0.0-py3-none-any.whl -
Subject digest:
c420c12457f57ea485dd38a768dc71cba1aec947800251d6cc203c663e1499d7 - Sigstore transparency entry: 1243626278
- Sigstore integration time:
-
Permalink:
apyatkin/personal-tools@86216a889da7dbf5da5c3a62973369153767c2ed -
Branch / Tag:
refs/tags/v2.0.0 - Owner: https://github.com/apyatkin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@86216a889da7dbf5da5c3a62973369153767c2ed -
Trigger Event:
push
-
Statement type: