Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
3f84fb4
Report each dev server's localhost and network URLs, and how to expos…
enso-works Oct 23, 2026
4304ec2
Run the Python tests in CI before building
enso-works Oct 23, 2026
54af45f
Show a QR code and network URL for dev servers in the menu bar app
enso-works Oct 23, 2026
7dcc7b9
Add QR code screenshots from demo data
enso-works Oct 23, 2026
8b59bf7
Document server URLs and QR codes
enso-works Oct 23, 2026
9262067
Release 0.5.0
enso-works Oct 23, 2026
25cc5dc
Give Storybook, Rsbuild and webpack a --host 0.0.0.0 hint, since thei…
enso-works Oct 23, 2026
2023351
Don't list Storybook among servers that listen on localhost by default
enso-works Oct 23, 2026
597a6c8
Link the article on opening localhost from a phone
enso-works Oct 23, 2026
a939539
Scan git worktrees for changes, merged branches and age, and remove t…
enso-works Oct 23, 2026
741df3c
Send worktrees from the bridge once a minute, with demo data that nev…
enso-works Oct 23, 2026
8442234
Add a Worktrees page, a project menu entry and a Needs you item for m…
enso-works Oct 23, 2026
0d30a65
Add the Worktrees screenshot and refresh the popover screenshots
enso-works Oct 23, 2026
411666a
Document worktrees
enso-works Oct 23, 2026
a64cf6c
Release 0.6.0
enso-works Oct 23, 2026
b729581
Leave the folder off the main checkout's row, the repository header s…
enso-works Oct 23, 2026
cba979a
Link the article on removing git worktrees
enso-works Oct 23, 2026
b1c7332
Retry stapler validate too, it hits the same flaky CloudKit lookup as…
enso-works Oct 23, 2026
00a37b1
Merge branch 'server-urls' into worktrees
enso-works Oct 23, 2026
c11b5d4
Retry hdiutil create, which fails now and then on CI runners
enso-works Oct 23, 2026
06e205b
Merge branch 'server-urls' into worktrees
enso-works Oct 23, 2026
207be38
Detect the package.json scripts and Procfile entries a project can run
enso-works Oct 24, 2026
e0c82dd
Supervise dev servers devdash starts: stop by process group, logs, re…
enso-works Oct 24, 2026
bebfd13
Bridge commands and snapshot fields for running scripts, with demo data
enso-works Oct 24, 2026
5b39437
Run, restart, stop and read logs of dev servers from the menu bar app
enso-works Oct 24, 2026
8138df5
Render Ready to run and the logs window, refresh screenshots
enso-works Oct 24, 2026
aed2b27
Release 0.7.0: run dev servers
enso-works Oct 24, 2026
512fb17
Show a port conflict in demo data and the README, with a shorter Need…
enso-works Oct 24, 2026
d8067c9
Link the article on killing the process on a port
enso-works Oct 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/macos-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ on:
paths:
- "macos/**"
- "devdash/**"
- "tests/**"
- "CHANGELOG.md"
- ".github/workflows/macos-app.yml"
pull_request:
paths:
- "macos/**"
- "devdash/**"
- "tests/**"
- "CHANGELOG.md"
- ".github/workflows/macos-app.yml"
workflow_dispatch:
Expand All @@ -36,6 +38,11 @@ jobs:
with:
fetch-depth: 0

- name: Python tests
run: |
python3 -m pip install --quiet psutil pytest
python3 -m pytest -q tests

- name: Check version and release notes
id: check
run: |
Expand Down
38 changes: 38 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,43 @@
# Changelog

## 0.7.0

### Added
- **Run dev servers**: a project's menu in Running has **Run dev** (the script you ran last, else `dev`, `start`, `serve` or `preview`) and a **Run** submenu with every package.json script, the dev scripts of workspace packages and the entries of `Procfile.dev` or `Procfile`. The package manager comes from the lockfile or the `packageManager` field.
- **Ready to run**: recent Claude Code projects with nothing running are listed at the bottom of Running, each with a play button.
- Servers devdash started get a chip with the script name, and Restart, Stop and Logs buttons. Stop ends the script's whole process group, so the servers `npm run dev` or turbo started stop with it.
- **Logs**: output goes to `~/.local/share/devdash/runs/<project>/<script>.log` (kept under 5 MB) and opens in the logs window, with filter, follow, Restart and Stop.
- **Restart when it crashes**, per server, off by default: restarts after 2 seconds, at most 3 times in 5 minutes.
- A crash shows up in Needs you with the exit code and a notification. Runs without a port (workers, watchers) and runs that ended keep a row in their project.
- When a port the script used last time is held by another process, the run doesn't start; Needs you names the process and offers **Stop and run**.
- Servers keep running when the menu bar app quits, like servers started in a terminal, and devdash picks them up again on the next launch.
- `devdash --serve` sends `runs`, `runnable` (when it changes) and each server's `run_id`, and has `run_script`, `stop_run`, `restart_run`, `clear_run` and `restart_on_crash` commands.

### Changed
- Stop All in a project stops the runs devdash started as a whole.
- Notifications for servers devdash started are about crashes only, not every start and stop.

## 0.6.0

### Added
- **Worktrees**: a page with every linked git worktree of the repositories devdash knows about (projects with something running and the Claude Code projects of every account), with the branch, who created it, when it was last touched, its size, and whether it's running, has changes, is merged, or is stale. Open it from the footer or from **Worktrees** in a project's menu.
- Remove a worktree from its row: `git worktree remove`, `git worktree prune`, and `git branch -d` for merged branches. Worktrees with changes, with a server or Claude session running in them, and the main checkout can't be removed.
- Branches count as merged when they are merged into the default branch or their remote branch is gone, so squash-merged pull requests are caught too.
- Needs you lists merged worktrees nothing has touched for a day.
- Projects that are linked worktrees get a stacked icon on their branch chip in Running.
- `devdash --serve` sends a `worktrees` list when it changes (scanned once a minute) and has `refresh_worktrees`, `worktree_size` and `remove_worktree` commands.

## 0.5.0

### Added
- **Server URLs and QR codes**: the QR button on a dev server, or Show QR Code in its menu, opens a page with the server's network URL as a QR code, so a phone on the same Wi-Fi opens it in one scan. It also lists the localhost and network URLs with copy and open buttons, and a port picker for servers with several ports.
- Servers that listen on localhost only say "Only this Mac can open it" and show how to fix that for their runtime, such as `--host` for Vite or `--host 0.0.0.0` for uvicorn.
- Server menus have Copy Network URL and Show QR Code. Option-click a port chip to copy its URL.
- `devdash --serve` reports each server's `urls` (port, localhost URL, network URL and whether other devices can reach it), an `expose_hint`, and the Mac's `lan_ip`.

### Changed
- Port chips, Open and Copy URL use https for servers that speak TLS, such as Vite with `--https`.

## 0.4.0

### Added
Expand Down
67 changes: 65 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ See and manage your dev servers, Docker containers and Claude Code sessions from
## Features

- **Dev servers**: every process listening on a port, in any language (Node, Bun, Deno, Python, Ruby, Go, Rust and more), with its memory, CPU and the project it belongs to. Local databases such as Homebrew Postgres show up as services.
- **Open on your phone**: each dev server's network URL and a QR code, so a phone on the same Wi-Fi opens it in one scan. Servers only this Mac can reach say so, with the flag that fixes it. See [Server URLs and QR codes](#server-urls-and-qr-codes).
- **Run dev servers**: start any package.json script or Procfile entry from the menu bar, then restart, stop and read its logs there. Optional restart on crash, and a warning when another process holds the port. See [Running dev servers](#running-dev-servers).
- **Git worktrees**: every linked worktree of the repositories you work in, such as the ones Claude Code creates, with uncommitted changes, merged branches and what runs in them. Remove the merged ones in one click. See [Worktrees](#worktrees).
- **Docker**: containers grouped by Compose stack, with status, health and ports.
- **Cleanup**: flags idle, orphaned and zombie processes and long-running containers, and lets you remove them in one click.
- **Disk tree**: a treemap of your home folder that shows what takes up space and suggests what you can safely reclaim.
Expand Down Expand Up @@ -77,8 +80,11 @@ What you can do:

- **Needs you**: one list at the top for anything that wants your attention: cleanup suggestions, low disk space, disk space worth a look, and plan limits over 80%. Dismiss an item and it stays hidden until it changes. The list disappears when there is nothing to show.
- **Running**: dev servers, Docker containers and Claude sessions, grouped by project (the git repository they run in). Each project header shows the branch and has a menu to open the project in your editor, Finder or Terminal, start a Claude session there, or stop everything in it. Services, servers outside any project and Node processes without a port are grouped at the bottom. Choose **Type** next to the filter to group by dev servers, Compose stacks, Claude sessions, services and background processes instead.
- Click a port chip to open `localhost:<port>`. Hover a row to open it in your editor or kill it (click twice to confirm). Right-click any row for all its actions.
- Click a port chip to open `localhost:<port>` (https when the server speaks it), or Option-click to copy the URL. Hover a row to open it in your editor or kill it (click twice to confirm). Right-click any row for all its actions.
- Click a server for process details: command, children, network connections, open files and environment. Click a container to stream its logs in a separate window, with filtering, follow mode and copy.
- **Run dev servers**: **Run dev** and a **Run** submenu in every project's menu, and recent projects under **Ready to run**. See [Running dev servers](#running-dev-servers).
- **Worktrees**: the footer button lists every linked git worktree, and Needs you shows merged ones nothing has touched for a day. See [Worktrees](#worktrees).
- **Server URLs**: right-click a server for Copy URL, Copy Network URL and Show QR Code, or hover it and click the QR button. See [Server URLs and QR codes](#server-urls-and-qr-codes).
- **System**: CPU, memory, disk, swap and network, the Disk tree summary, and the top processes sorted by memory or CPU. The header shows CPU and memory on every tab; click it to open this tab.
- **Claude**:
- plan limits and API-equivalent cost;
Expand All @@ -88,9 +94,61 @@ What you can do:
- **Footer**: Disk tree, dependency graph and activity heatmap. The `...` menu has JSON export, the terminal UI, What's new, Check for updates and Quit.
- **Keep awake**: the cup in the header. While it's on, the Mac doesn't sleep, and after 50 seconds without input devdash moves the cursor one point and back, too fast to see, so Teams and Slack keep you active. Moving the cursor needs Accessibility access, which macOS asks for the first time you turn it on; without it only the sleep prevention works. It stays on across restarts. More in [Mouse jiggler for Mac](https://bavrk.com/articles/mouse-jiggler-for-mac).
- **Keyboard**: Cmd+1 to Cmd+3 switch tabs, Cmd+F filters, Esc clears the filter.
- **Notifications**: a macOS notification when a dev server starts or exits, a container stops, or a watched port comes up.
- **Notifications**: a macOS notification when a dev server starts or exits, a container stops, a watched port comes up, or a server devdash started crashes.
- **Settings**: launch at login, editor (VS Code or Cursor), whether the menu bar shows the count and usage percentage, notifications, and a custom `devdash` path.

### Server URLs and QR codes

| Open on your phone | Localhost only |
|---|---|
| ![QR code for a dev server](screenshots/app/qrcode.png) | ![A server only this Mac can reach](screenshots/app/qrcode-localhost.png) |

To try a dev server on your phone, hover it in Running and click the QR button, then scan the code with the phone's camera. The phone has to be on the same Wi-Fi as the Mac. The page also lists the server's localhost and network URLs with copy and open buttons, and a port picker when the server listens on more than one.

A phone can only reach a server that listens on all interfaces (`0.0.0.0` or `::`). Vite, Astro, uvicorn, Rails and many other dev servers listen on `localhost` by default, so the page says "Only this Mac can open it" and shows the flag for that server, such as `--host` for Vite or `--host 0.0.0.0` for uvicorn. If the code still doesn't open, check that the macOS firewall allows incoming connections for the server's runtime (System Settings > Network > Firewall).

The network address is the Mac's private IPv4 address on Wi-Fi or Ethernet. VPN tunnels are skipped. More in [How to access localhost from your phone](https://bavrk.com/articles/access-localhost-from-phone).

### Running dev servers

| Ready to run | Port in use |
|---|---|
| ![Recent projects with a play button](screenshots/app/ready.png) | ![Needs you offering to stop the process that holds the port](screenshots/app/port-conflict.png) |

![The logs window of a server devdash started](screenshots/app/logs.png)

Every project in Running has **Run dev** in its menu (the `...` on its header, or right-click), plus a **Run** submenu with everything it can run:

- the scripts in its `package.json`, run with the package manager its lockfile or `packageManager` field names (npm, pnpm, yarn or bun);
- the `dev`, `start`, `serve` and `preview` scripts of its workspace packages (`workspaces` in package.json, or `pnpm-workspace.yaml`);
- the entries of `Procfile.dev`, or `Procfile` when there is no `Procfile.dev`.

**Run dev** starts the script you ran last in that project, or else the first of `dev`, `start`, `serve` and `preview`. Recent Claude Code projects with nothing running are listed under **Ready to run** at the bottom of Running, with a play button.

Scripts run in your login shell's environment, so nvm, fnm, mise and asdf pick the same Node or Python as in a terminal. A server devdash started gets a chip with the script name and three buttons: **Restart**, **Stop** and **Logs**. Stop sends SIGTERM to the script's whole process group and SIGKILL after 5 seconds, so the servers `npm run dev` or turbo started stop too. The output goes to `~/.local/share/devdash/runs/<project>/<script>.log`, which devdash keeps under 5 MB, and the logs window follows it with a filter.

Right-click a server devdash started and choose **Restart When It Crashes** to have devdash bring it back 2 seconds after it exits with an error, at most 3 times in 5 minutes. A crash also shows up in Needs you with its exit code and a link to the logs. Runs that have no port yet, such as workers, and runs that ended stay in their project with their status until you remove them.

Before a run starts, devdash checks the ports it used last time (and any `--port`, `-p` or `PORT=` in the script). When another process holds one, the run doesn't start and Needs you says which process it is, with **Stop and run**. devdash never stops a process you didn't ask it to. More in [Kill the process on a port on Mac](https://bavrk.com/articles/kill-process-on-port).

Servers keep running when you quit the menu bar app, like servers started in a terminal. devdash picks them up again on the next launch, but can only restart a crashed server while it's running.

### Worktrees

![Worktrees](screenshots/app/worktrees.png)

Coding agents create a git worktree per task and rarely clean up after themselves. The Worktrees page (in the footer, or **Worktrees** in a project's menu) lists every linked worktree of the repositories devdash knows about: projects that have something running, and your Claude Code projects in every account. Repositories without linked worktrees are left out.

Each worktree shows its branch, which tool created it (Claude Code worktrees get the Claude mark), when it was last touched, its size, and a status:

- **Running**: a dev server or Claude session is running in it.
- **Changes**: it has uncommitted or untracked files.
- **Merged**: its branch is merged into the default branch (`origin/main` when there is a remote), or its remote branch is gone, which is what a squash merge on GitHub leaves behind.
- **Stale**: untouched for a week.
- **Active**: everything else.

Remove a worktree from its row or right-click menu. devdash runs `git worktree remove`, then `git worktree prune`, and for merged branches `git branch -d`, which keeps a branch git doesn't consider merged (squash merges) and says so. It never forces anything: worktrees with changes, with something running in them, locked ones and the main checkout can't be removed from devdash. Merged worktrees nothing has touched for a day also appear under Needs you. More in [git worktree remove: clean up worktrees without --force](https://bavrk.com/articles/git-worktree-remove).

### Disk tree

![Disk tree](screenshots/app/disk-tree.png)
Expand Down Expand Up @@ -320,6 +378,11 @@ devdash/
processes.py # process, Docker, system and Claude Code data collection
claude_usage.py # plan limits and API-equivalent cost from transcripts
claude_profiles.py # Claude Code profiles from ~/.config/claude-profiles
servers.py # dev servers in any language and the project each belongs to
network.py # LAN address and the network URL of each server
worktrees.py # git worktrees across repositories, and removing them safely
runnable.py # package.json scripts and Procfile entries a project can run
supervisor.py # dev servers devdash starts: restart, stop, logs, restart on crash
bridge.py # JSON-lines bridge for the menu bar app (--serve)
demo.py # synthetic data for --demo and screenshots
cli.py # command-line entry point
Expand Down
2 changes: 1 addition & 1 deletion devdash/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.4.0"
__version__ = "0.7.0"
Loading
Loading