Tejas GK

Mac Dev Doctor CLI

Tejas GK| (3mo ago)

10 min read

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.