Forem

Bora Kilicoglu
Bora Kilicoglu

Posted on

ferman: A Tiny CLI for Inspecting and Freeing Busy Ports

Busy ports are one of those tiny problems that interrupt real work far more often than they should.

You start a dev server, a local database, a preview app, or a test runner, and something fails because a port is already in use. Then the usual dance begins:

  • check what is using the port
  • figure out whether it is safe to stop
  • kill the process
  • retry your actual work

That friction is exactly why I built ferman.

ferman is a small cross-platform CLI for inspecting busy ports, identifying the process behind them, and freeing them safely.

It is built for developers, but also for AI agents, scripts, and local automation workflows that need deterministic output and low ambiguity.

Why I built it

The core problem is simple:

  • a port is occupied
  • you need to know what is using it
  • you may want to free it

There are already OS-level commands for this, but they are not consistent across platforms, and they are not especially friendly for automation.

On macOS and Linux you might use lsof.
On Windows you might use netstat, tasklist, and taskkill.
If you are scripting around those commands, you also end up dealing with parsing, platform branching, and error handling.

I wanted one clean command that:

  • works across platforms
  • stays small
  • is readable for humans
  • is structured for machines

What ferman does

At the simplest level:

npx ferman 3000
Enter fullscreen mode Exit fullscreen mode

It validates the port, checks whether it is busy, identifies the matching process when possible, and asks before termination.

There are a few core modes:

ferman 3000
ferman 3000 --force
ferman 3000 --dry
ferman 3000 --json
ferman 3000 --toon
Enter fullscreen mode Exit fullscreen mode

It also supports more AI-oriented flows:

ferman 3000 5173 5432 --json
ferman --common --json
ferman --plan --json
ferman --doctor --json
ferman --json-schema
ferman 3000 --watch --json
Enter fullscreen mode Exit fullscreen mode

Built for humans and agents

One thing I cared about from the start was making the tool work well in two very different contexts:

  1. a developer using a terminal manually
  2. a script, CI job, or AI agent using structured output

For humans, the CLI stays minimal and readable.

For machines, the output is deterministic and stable.

Example JSON output:

{
  "ok": true,
  "code": "PORT_RELEASED",
  "port": 3000,
  "busy": true,
  "processes": [
    {
      "pid": 1234,
      "name": "node"
    }
  ],
  "action": "killed",
  "message": "Port released."
}
Enter fullscreen mode Exit fullscreen mode

Example error output:

{
  "ok": false,
  "code": "INVALID_PORT",
  "message": "Port must be a whole number."
}
Enter fullscreen mode Exit fullscreen mode

That matters because once the output contract is stable, the CLI becomes much easier to compose into larger workflows.

AI-facing features

Over time, I pushed the project beyond the original “free a port” use case.

The current AI-facing surface includes:

  • strong JSON contract
  • stable machine error codes
  • TOON output for compact LLM-oriented structured data
  • multi-port support
  • --common for common local development ports
  • --plan for recommendation output
  • --doctor for local environment diagnosis
  • --json-schema for machine contract discovery
  • --watch for repeated snapshot events

This makes ferman more useful for:

  • local AI coding agents
  • shell automation
  • CI helpers
  • internal dev tooling
  • MCP-style wrappers and structured integrations

A few examples

Inspect without changing anything:

ferman 3000 --dry
Enter fullscreen mode Exit fullscreen mode

Release immediately:

ferman 3000 --force
Enter fullscreen mode Exit fullscreen mode

Check several ports at once:

ferman 3000 5173 5432 --json
Enter fullscreen mode Exit fullscreen mode

Scan common dev ports:

ferman --common --json
Enter fullscreen mode Exit fullscreen mode

Ask for the recommended next step:

ferman 3000 --plan --json
Enter fullscreen mode Exit fullscreen mode

Get the output schema for integrations:

ferman --json-schema
Enter fullscreen mode Exit fullscreen mode

Watch a port over time:

ferman 3000 --watch --json
Enter fullscreen mode Exit fullscreen mode

Under the hood

The project is built in TypeScript and keeps dependencies intentionally small.

Platform-specific behavior is abstracted behind separate adapters:

  • macOS
  • Linux
  • Windows

The docs are built with VitePress, tests run with Vitest, and the package is published through GitHub Actions with trusted publishing.

I also added:

  • ESLint
  • Prettier
  • Husky
  • smoke checks
  • release checks

So even though the tool is small, the release workflow is treated seriously.

What I like about the result

I like that ferman stays narrow.

It does not try to be a general system monitor or a giant process manager.
It focuses on one annoying workflow and makes it much easier:

  • find what is using a port
  • understand whether action is needed
  • free the port when appropriate

That is enough to be useful every day.

Try it

If you want to try it:

npx ferman 3000
Enter fullscreen mode Exit fullscreen mode

Project links:

If you build internal tooling, local automation, or AI-assisted developer workflows, I think this kind of CLI surface is worth investing in.

Small tools with predictable interfaces compound well.

Top comments (0)