lohost Coming soon
Help

How lohost works, and what it asks for

Installing

lohost is not released yet. The first build will be announced at github.com/lohost-dev. Once it is out, there will be two ways to install it:

  1. From the disk image. On the download page, pick the image for your Mac’s chip, open it, and drag lohost to Applications.
  2. With Homebrew. brew install --cask lohost-dev/tap/lohost installs the same disk image and puts the lohost command on your PATH.

The first time you open it, macOS asks whether you want to open an app downloaded from the Internet. lohost is signed with its developer’s ID and notarized by Apple, so the same dialog says Apple checked it for malicious software. Click Open. If macOS says instead that it is damaged or cannot be checked, the download is incomplete or has been changed: delete it, download it again, and compare its SHA-256 with the one on the download page.

lohost needs macOS 13 or later, on Apple silicon or Intel.

The menu-bar item

A ring with a bead in its opening, and a small word over a number:

  • LIVE and an ink bead: all is calm, and the number is how many servers are running — dev servers, databases, containers and tunnels. An app’s own helpers are listed under Apps and never counted.
  • LOOK and an amber bead: something to watch, such as a server an agent left running.
  • LOOK and a red bead: something is broken or exposed. The number says how many things need a look.

Click it for the list. Trouble comes first, each with its way out; then every server, grouped by project; then apps, folded away. A keyboard shortcut opens the same list from anywhere with the cursor in search: type a port, a project, a branch or an agent. The switch at the top groups the same rows by who started them instead.

Who started it

No single source knows every server, so lohost reads several and keeps the strongest answer:

  1. The stamp in the environment. Claude Code, Codex, Cursor’s agent, Gemini CLI, Copilot CLI, opencode and others put a marker in the environment of each command they run. It is fixed when the server starts, so it still says whose it is after the agent has exited.
  2. The agents’ own session files, read-only, to name the session and say whether it is busy or has ended.
  3. The chain of parent processes, up to the app it runs in: Terminal, iTerm2, Ghostty, Warp, WezTerm, kitty, an editor, tmux.
  4. Docker, launchd and ssh, which describe their own: the compose project and service, the job’s label and run count, the tunnel’s destination.
  5. Who is connected: an app or an MCP server using a port says what the port is for.

Each tool’s own per-command marker is checked before the generic ones, because an editor can put Claude Code’s variable into every terminal it opens, including the ones you type in yourself.

Why a column says —

A — means nothing on your Mac said. lohost never shows a guess as a fact. The common cases:

  • macOS’s own programs, such as /bin/zsh or /usr/bin/ssh, do not let other processes read their environment, so there is no stamp to read. lohost follows the parent chain instead, as far as it goes.
  • Processes that belong to root or another user are visible only by name and process ID. Their folder, branch and starter are out of reach without an administrator, and lohost never asks for one.
  • A folder that is not a git repository has no branch.

What “needs a look” means

  • A crash loop. launchd restarts a job that exits, and one that exits cleanly never shows as failed. lohost sees its run count climb, and says how many restarts it has made.
  • Can’t start. When a job’s log says its port is taken, lohost shows that line and names what holds the port.
  • Left running. The agent session that started a server has ended, and the server is still up. Stop it, or keep it; kept servers stop being mentioned.
  • Open to your network. The server listens on every address, not only on this Mac. lohost shows the flag or setting that made it so, and whether the macOS firewall is on. A database, a model server or a debugger port is flagged; a dev server that listens widely by default gets a quiet mark instead.
  • Twice. The same script running twice from the same folder.

Stopping a server

lohost looks freely and acts only when you click, and only on the exact process you saw:

  • Identity first. The process ID and start time must still match what you clicked, so a process ID macOS has since given to something else is never signalled.
  • The whole server. The stop signal goes to the server’s own process group (npm, node and its workers together), never to a name or a pattern such as pkill node.
  • Force takes a second click, offered after five seconds if the server has not stopped.
  • The right tool. A container stops through Docker, a launchd job through launchctl, a brew service through brew services.
  • Never a process that belongs to root or to macOS, or an app’s own helper. For those you get Quit app, or a command to copy.

The lohost command

Everything the list shows, in a terminal, for you, a script or an agent. The Homebrew cask links it onto your PATH; from the disk image it is inside the app, and Settings → Advanced can link it for you.

lohost ls              # every server, trouble first (--all adds apps)
lohost why 3000        # what holds :3000, whose it is, and why it won’t start
lohost free 3000       # the next free port from 3000
lohost port            # a steady port for this folder or worktree
lohost ls --json       # every command also speaks JSON
/Applications/lohost.app/Contents/Resources/bin/lohost ls   # without the link

It is a short POSIX shell script. It holds no data of its own: it asks the running app over a Unix socket in lohost’s own folder, ~/Library/Application Support/lohost/lohost.sock.

MCP for Claude Code, Codex and Cursor

The same command speaks MCP, so an agent can ask what is running before it starts something. Its tools list the servers, say what holds a port, find a free port, list the servers the asking session started, and stop one of those — and only those: the agent’s session ID travels with each request, so a session can never stop a server another session or you started.

Claude Code, in a terminal:

claude mcp add lohost -- /Applications/lohost.app/Contents/Resources/bin/lohost mcp

Codex, in ~/.codex/config.toml:

[mcp_servers.lohost]
command = "/Applications/lohost.app/Contents/Resources/bin/lohost"
args = ["mcp"]

Cursor, in ~/.cursor/mcp.json:

{
  "mcpServers": {
    "lohost": {
      "command": "/Applications/lohost.app/Contents/Resources/bin/lohost",
      "args": ["mcp"]
    }
  }
}

If lohost lives somewhere other than /Applications, use that path. The Claude Code plugin below includes the MCP server, so with the plugin you need neither line.

The Claude Code plugin

One plugin with three hooks and the MCP server. It is off until you install it.

  • Before a dev server starts (a PreToolUse hook on Bash), lohost checks whether the same one is already running for that folder. By default it warns Claude Code and lets the command run; with Block duplicates on, it stops the command and says where the running one is. For any other command it says nothing.
  • When a session starts, it can hand the worktree a steady port, as PORT in the session’s environment.
  • When a session ends, lohost hears it at once, so what the session left running is found straight away: a notification offers Stop or Keep.

Each hook gives up after a second (three when a session starts), so a busy or closed app never slows Claude Code down, and if lohost is not running the hooks do nothing.

Installing it. Settings → Agents in lohost installs it. Installing a plugin writes to your Claude Code settings, so lohost shows you the change and asks first. To do the same by hand, from Claude Code:

/plugin marketplace add /Applications/lohost.app/Contents/Resources/integrations
/plugin install lohost@lohost

To remove it: /plugin uninstall lohost@lohost, or the same card in Settings → Agents.

Permissions

Seeing what listens, whose it is and what branch it is on takes no permission at all. The rest is asked for only when you use it:

WhatWhen macOS asks
At installNothing. No admin password, no system extension, no helper installed with root.
AutomationThe first time you use Show tab for a server in Terminal, iTerm2 or Ghostty: macOS asks once per terminal app whether lohost may control it. WezTerm, kitty, tmux, Warp and editors are reached through their own commands and ask nothing. Change it in System Settings → Privacy & Security → Automation.
NotificationsOnly if you turn them on, for trouble and for what a session left running.
Open at loginOnly if you turn it on.
Local networkNever: lohost checks servers only at your Mac’s own address, never across your network.
Full Disk Access, Accessibility, Screen RecordingNot needed.

Updates

lohost checks dl.lohost.dev for a new version and updates itself, whether it came from the disk image or from Homebrew. That check is its only request to anything outside your Mac; the privacy page says exactly what it sends. Keep lohost in Applications: macOS does not let a copy that runs from the disk image or from Downloads replace itself.

Uninstalling

  1. If you installed the Claude Code plugin, remove it first (above). MCP entries you added by hand stay in your agents’ configuration until you delete them.
  2. Quit lohost from its menu, then drag it from Applications to the Trash.
  3. Its files stay until you delete them: ~/Library/Application Support/lohost, ~/Library/Logs/lohost, ~/Library/Caches/lohost-updater and ~/Library/Preferences/dev.lohost.app.plist.
  4. With Homebrew, brew uninstall --cask lohost removes the app, and brew uninstall --zap --cask lohost deletes those files too.

Questions

Does it need an administrator password?

No. It reads your own processes as you. Processes that belong to root are shown by name and process ID only, and never stopped; lohost gives you the command to run yourself.

It says Claude Code, but I typed that command myself.

Editors with Claude Code’s extension can mark every terminal they open with Claude Code’s variable. lohost looks for each agent’s per-command marker before that one and falls back to the terminal, but if a row still names the wrong starter, please report it with the agent and the editor you used.

Why does a server count as open to my network?

It listens on every address (0.0.0.0 or ::), not only on 127.0.0.1. Whether another device can actually reach it also depends on the macOS firewall, which lohost shows next to it.

Why isn’t it on the App Store?

The App Store’s sandbox would not let lohost see other apps’ processes or stop them, which is the whole job.

Reporting a problem

Open an issue at github.com/lohost-dev/lohost/issues and say what you saw, what you expected, and which agent, terminal or tool started the server.

Never paste environment variables, a token or a configuration file such as ~/.claude.json into an issue: they can hold secrets. Nobody working on lohost will ask for one.