Mac Dev Doctor CLI
Tejas GK| (3mo ago)
A lightweight terminal toolkit for inspecting, maintaining, and automating a macOS development environment.
The toolkit is built entirely with shell functions and standard macOS/Unix utilities such as:
top
vm_stat
df
pmset
system_profiler
ping
lsof
find
du
grep
awk
sed
git
curl
python3
osascript
caffeinate
The goal is simple:
Run one command in the terminal and quickly understand what is happening on the machine.
The toolkit also includes several standalone commands for common developer tasks such as killing ports, keeping the Mac awake, inspecting large files, copying files to the clipboard, generating passwords, serving directories locally, and checking Git repositories.
Installation
Add the script to:
~/.zshrc
Then reload your shell:
source ~/.zshrc
After that, the main command becomes available:
doctor
By default, the toolkit assumes your development projects live inside:
~/Projects
This is configured using:
DOCTOR_PROJECTS="$HOME/Projects"
If your projects live somewhere else, change this value.
For example:
DOCTOR_PROJECTS="$HOME/Developer"
Main Command
The primary command is:
doctor
This runs a complete development-machine health report.
It includes:
System information
Network information
Developer tools
Listening ports
Git repository status
Disk usage
Development storage usage
Example:
doctor
Example output:
==============================================
MAC DEV DOCTOR
==============================================
SYSTEM
----------------------------------------------
macOS: 15.x
Architecture: arm64
CPU: 8% user, 4% sys, 88% idle
RAM: 9GB / 16GB
Disk: 173Gi used / 228Gi total
Uptime: 2 days
Battery: 84% (discharging)
Cycles: 120
NETWORK
----------------------------------------------
Local IP: 192.168.1.20
Gateway: 192.168.1.1
Internet: ✓ Connected
Ping: 18 ms
DEV
----------------------------------------------
Node: v24.x
npm: 11.x
Git: 2.x
Python: 3.x
Docker: 28.x
Homebrew: 4.x
PORTS
----------------------------------------------
PROCESS PID PORT
node 2812 3000
postgres 982 5432
GIT
----------------------------------------------
⚠ website
M package.json
1 repository has changes.
SPACE
----------------------------------------------
node_modules: 8.21 GB
Homebrew cache: 1.03 GB
macOS caches: 4.43 GB
Doctor Commands
Full report
doctor
Runs every major diagnostic section.
Equivalent to checking:
System
Network
Developer environment
Ports
Git repositories
Disk usage
Network
doctor network
Displays network diagnostics.
It checks:
Local IP
Default gateway
Internet connectivity
Ping latency
DNS server
Example:
NETWORK
----------------------------------------------
Local IP: 192.168.1.20
Gateway: 192.168.1.1
Internet: ✓ Connected
Ping: 21 ms
DNS: 192.168.1.1
Internet connectivity is tested using:
ping 1.1.1.1
This checks network access without depending on DNS resolution.
Developer Environment
Run:
doctor dev
The command checks whether common development tools are installed.
Currently supported:
Node.js
npm
Git
Python
Docker
Homebrew
It also checks whether the Docker daemon is actually running.
Example:
DEV
----------------------------------------------
Node: v24.1.0
npm: 11.3.0
Git: 2.49.0
Python: 3.13.2
Docker: 28.0.1
Homebrew: 4.4.0
Docker daemon: ✓ Running
If something is missing:
Docker: ✗ Not installed
Ports
Show listening ports
doctor ports
or:
ports
This uses lsof to show processes currently listening for TCP connections.
Example:
PROCESS PID PORT
node 18293 3000
postgres 823 5432
redis-server 991 6379
This is useful when a development server refuses to start because a port is already occupied.
Inspect a Specific Port
Use:
whoport 3000
Example:
COMMAND PID USER FD TYPE
node 18293 user 25u IPv6
This tells you exactly what process owns that port.
Kill a Process on a Port
Use:
killport 3000
The command first displays the process.
Example:
Process:
PID COMMAND
18293 node server.js
Kill PID 18293? [y/N]
If confirmed, the process is terminated.
This is safer than blindly doing:
kill -9 $(lsof -ti:3000)
because you get to inspect the target before killing it.
Git Repository Health
Run:
doctor git
or:
gitdirty
The command scans:
~/Projects
for Git repositories.
It detects repositories containing:
Modified files
Deleted files
New files
Staged files
Uncommitted changes
Example:
GIT
----------------------------------------------
⚠ tejasgk
M package.json
M src/app/page.tsx
⚠ search-engine
?? notes.txt
2 repositories have changes.
If everything is clean:
✓ All repositories clean
This is useful before:
shutting down
switching machines
travelling
updating macOS
cleaning projects
Disk Diagnostics
Run:
doctor disk
This analyzes development-related disk usage.
It currently checks:
node_modules
Docker
Homebrew cache
macOS user caches
Largest files in Downloads
Example:
SPACE
----------------------------------------------
node_modules: 11.82 GB
Homebrew cache: 932 MB
macOS caches: 5.12 GB
Find All node_modules
Use:
nodemodules
Example:
1.8G ~/Projects/project-a/node_modules
1.1G ~/Projects/project-b/node_modules
740M ~/Projects/project-c/node_modules
This is particularly useful for JavaScript developers because abandoned node_modules directories can quietly consume tens of gigabytes.
You can also pass another directory:
nodemodules ~/Developer
Find Large Files
Run:
bigfiles
By default, this searches your home directory.
You can scope it:
bigfiles ~/Downloads
or:
bigfiles ~/Projects
It displays the thirty largest files it finds.
Example:
4.8G ~/Downloads/video.mov
2.1G ~/Downloads/archive.zip
870M ~/Projects/test/database.dump
Cleanup Mode
Run:
doctor clean
This opens an interactive cleanup menu.
Example:
MAC DEV DOCTOR CLEANUP
==============================================
1) Homebrew cache
2) Docker unused data
3) Old node_modules
4) macOS user caches
5) Everything above
6) Cancel
Destructive cleanup actions ask for confirmation.
Homebrew Cleanup
From:
doctor clean
choose:
1
This runs:
brew cleanup
It removes old cached Homebrew downloads and outdated package versions that Homebrew no longer needs.
Docker Cleanup
Select Docker cleanup through:
doctor clean
The script first displays Docker disk usage:
docker system df
Then asks before running cleanup.
The cleanup uses:
docker system prune
This can remove:
Stopped containers
Unused networks
Dangling images
Build cache
It does not automatically delete everything without confirmation.
Remove node_modules
The cleanup system can locate every:
node_modules
directory inside your project directory.
It shows their sizes first.
Then it asks:
Delete ALL node_modules inside ~/Projects? [y/N]
If confirmed, the directories are removed.
Dependencies can later be restored with commands such as:
npm install
or:
pnpm install
or:
yarn
depending on the project.
Keep the Mac Awake
Use:
awake
This keeps the Mac awake indefinitely.
Stop it using:
Ctrl + C
You can also specify a duration.
Two hours:
awake 2h
Thirty minutes:
awake 30m
Internally, this uses the native macOS command:
caffeinate
This is useful during:
Large downloads
Long builds
Docker jobs
Video encoding
Deployments
Data processing
Backups
macOS Notifications
Send a notification directly from the terminal:
notify build finished
This uses AppleScript:
osascript
and displays a regular macOS notification.
You can combine it with shell commands:
npm run build && notify build finished
Run a Command and Notify When Finished
Instead of manually chaining commands, use:
runnotify npm run build
The command executes:
npm run build
and sends a macOS notification when it finishes.
Successful command:
npm completed successfully
Failed command:
npm failed with exit code 1
This is useful for long-running operations when you want to switch to another application while they run.
Examples:
runnotify npm run build
runnotify npm test
runnotify docker build .
Serve the Current Directory
Run:
serve
The current directory becomes a local HTTP server.
Default port:
8000
Open:
http://localhost:8000
Specify another port:
serve 3001
This internally uses:
python3 -m http.server
Useful for quickly previewing:
HTML files
Static websites
Generated files
JSON files
Images
Documentation
without creating a proper server.
JSON Formatter
Pretty-print a JSON file:
json response.json
Example input:
{"name":"Tejas","active":true,"skills":["JS","Go"]}
Output:
{
"name": "Tejas",
"active": true,
"skills": [
"JS",
"Go"
]
}
The command uses:
python3 -m json.tool
If no file is provided:
json
it reads JSON from the macOS clipboard.
So you can copy ugly JSON from a browser and simply run:
json
Clipboard Utilities
macOS includes:
pbcopy
pbpaste
The toolkit wraps them with simpler commands.
Copy a file
clip config.json
The contents of the file are copied to the clipboard.
You can then paste normally using:
Cmd + V
View clipboard contents
Run:
clip
with no arguments.
The clipboard contents are printed in the terminal.
Save clipboard to a file
saveclip response.json
This writes the current clipboard contents into:
response.json
Useful workflow:
Copy API output
↓
saveclip response.json
↓
json response.json
UUID Generator
Run:
uuid
Example:
8e976df4-7cab-4b9b-bf50-b746eae63ed3
This uses macOS's built-in:
uuidgen
and converts the output to lowercase.
Useful for:
Database IDs
Test data
API development
Mock objects
Temporary identifiers
Password Generator
Generate a random password:
password
Default length:
24
Example:
Yjs7!B9x#8w2sN$kV4QpX2_r
Specify length:
password 40
The generator reads cryptographically random bytes from:
/dev/urandom
and filters them into a password-safe character set.
File Hashing
Generate a SHA-256 hash:
hashfile archive.zip
Example:
6d7cc5a37e36fe0d...
This uses:
shasum -a 256
Useful for:
Verifying downloads
Comparing files
Detecting corruption
Checking release binaries
Duplicate detection
Help
Run:
doctor help
This displays all available commands.
Command Reference
CommandDescriptiondoctorFull Mac development health reportdoctor networkNetwork diagnosticsdoctor devDevelopment tool versionsdoctor portsShow listening TCP portsdoctor gitShow Git repositories with changesdoctor diskDevelopment disk usagedoctor cleanInteractive cleanupdoctor helpShow documentation summaryportsShortcut for port listingwhoport 3000Inspect a specific portkillport 3000Kill process using a portgitdirtyShow dirty repositoriesnodemodulesFind all node_modules directoriesbigfilesFind large filesawakeKeep Mac awake indefinitelyawake 2hKeep Mac awake for two hoursawake 30mKeep Mac awake for thirty minutesnotify messageSend macOS notificationrunnotify commandNotify after command completionserveServe current directory on port 8000serve 3001Serve current directory on custom portjson file.jsonPretty-print JSONjsonPretty-print clipboard JSONclip file.txtCopy file contentsclipPrint clipboardsaveclip file.txtSave clipboard to fileuuidGenerate UUIDpasswordGenerate random passwordpassword 40Generate 40-character passwordhashfile file.zipCalculate SHA-256
Architecture
The toolkit intentionally does not use a framework.
The architecture is roughly:
Warp / Terminal
│
↓
zsh
│
↓
doctor()
│
├── doctor_system
├── doctor_network
├── doctor_dev
├── doctor_ports
├── doctor_git
└── doctor_disk
│
↓
macOS / Unix commands
The main function works as a command router:
doctor() {
case "$1" in
clean)
doctor_clean
;;
ports)
doctor_ports
;;
git)
doctor_git
;;
disk)
doctor_disk
;;
dev)
doctor_dev
;;
network)
doctor_network
;;
help)
doctor_help
;;
*)
doctor_full
;;
esac
}
This gives the CLI a familiar subcommand structure:
doctor network
doctor git
doctor clean
similar to tools such as:
git status
docker ps
npm install
brew update
Why Build This?
Most of the information exposed by Mac Dev Doctor already exists somewhere in macOS.
The problem is that it is spread across many different commands.
For example:
top
for CPU.
vm_stat
for memory.
pmset
for battery.
lsof
for ports.
git status
for repositories.
du
for disk usage.
ping
for connectivity.
Mac Dev Doctor simply combines these small Unix tools behind a single interface.
Instead of remembering ten commands, I can run:
doctor
The project follows a basic Unix philosophy:
Small tools already do the work. The script simply composes them into something more useful.
Moving Beyond .zshrc
During development, keeping the functions in:
~/.zshrc
is convenient.
However, once the toolkit grows, it is better to move it into its own project.
For example:
~/Projects/mac-dev-doctor/
├── bin/
│ └── doctor
├── lib/
│ ├── system.sh
│ ├── network.sh
│ ├── git.sh
│ ├── disk.sh
│ └── utilities.sh
├── README.md
└── LICENSE
Then add:
export PATH="$HOME/Projects/mac-dev-doctor/bin:$PATH"
to:
~/.zshrc
Now doctor behaves like a regular command installed on the machine.
That also makes the project easier to:
Version with Git
Publish on GitHub
Install on another Mac
Share with other developers
Extend without bloating .zshrc
Philosophy
Mac Dev Doctor is not meant to replace proper monitoring software.
It is a personal developer utility.
The idea is to turn repetitive terminal commands into a small interface tailored to the machine I actually use.
Instead of repeatedly searching:
How do I find what's using port 3000 on macOS?
I run:
whoport 3000
Instead of:
How do I prevent my Mac from sleeping during this build?
I run:
awake 2h
Instead of manually checking twenty repositories before shutting down:
gitdirty
Instead of remembering how to create a temporary local web server:
serve
Once a repetitive action becomes a command, I no longer have to think about how to perform it.
I just use it.
That is the real point of the toolkit.