Dev Server — Start & Monitor
Start the project's dev server and watch its output for errors. The user says "start dev" and you handle detection, startup, and monitoring — they only hear from you when something breaks.
When a server supports a task, resolve ../setup/references/task-context.md and record
the command, port, monitor/session identifier and verification result there. A standalone
server start uses session state only and does not create a task.
Workflow
1. Detect the stack
Scan the working directory for project markers. Check in this order — first match wins:
| Marker file |
Stack |
Dev command |
Default port |
package.json |
Node.js (see framework table) |
varies |
3000 |
manage.py |
Django |
python manage.py runserver |
8000 |
Pipfile or pyproject.toml with [tool.poetry] |
Python (check for framework) |
varies |
8000 |
requirements.txt with fastapi |
FastAPI |
uvicorn main:app --reload |
8000 |
requirements.txt with flask |
Flask |
flask run --reload |
5000 |
Gemfile with rails |
Rails |
bin/rails server |
3000 |
Gemfile with sinatra |
Sinatra |
ruby app.rb |
4567 |
go.mod |
Go |
go run . |
8080 |
Cargo.toml |
Rust |
cargo run |
8080 |
pom.xml |
Maven/Spring |
./mvnw spring-boot:run |
8080 |
build.gradle / build.gradle.kts |
Gradle/Spring |
./gradlew bootRun |
8080 |
mix.exs with phoenix |
Phoenix |
mix phx.server |
4000 |
composer.json with laravel |
Laravel |
php artisan serve |
8000 |
docker-compose.yml |
Docker |
docker compose up |
varies |
Makefile with dev target |
Make |
make dev |
varies |
Node.js framework detection — when package.json exists, check dependencies:
| Dependency |
Framework |
Default command |
next |
Next.js |
next dev |
vite or @vitejs/* |
Vite |
vite |
@remix-run/dev |
Remix |
remix dev |
astro |
Astro |
astro dev |
@sveltejs/kit |
SvelteKit |
vite dev |
nuxt |
Nuxt |
nuxt dev |
@angular/cli |
Angular |
ng serve |
gatsby |
Gatsby |
gatsby develop |
expo |
Expo |
expo start |
| (none match) |
npm scripts |
<pm> run dev |
Node.js package manager — check in order:
bun.lock or bun.lockb → bunx / bun run
pnpm-lock.yaml → pnpm exec / pnpm run
yarn.lock → yarn / yarn run
- Default →
npx / npm run
Python environment — check in order:
.venv/ or venv/ exists → source .venv/bin/activate &&
poetry.lock → poetry run
Pipfile.lock → pipenv run
- Default → direct command
If nothing matches, tell the user you couldn't detect the stack and ask what command to run.
If the detection picks a stack that seems wrong for the directory (e.g. package.json exists but it's just dev tooling in a Python project, or both manage.py and package.json present and unclear which is primary), show the user your guess and confirm before starting. Don't silently commit to a wrong stack.
2. Pre-flight checks
Before starting:
Port conflict — check if the default (or user-specified) port is taken:
lsof -i :<port> -t 2>/dev/null
If occupied, identify the occupying process (ps -p <pid>) and present two options to
the user: kill PID N, or bind to port+1. Never kill a process without authorization. If
the process is clearly another instance of this project, prefer port+1 when no choice is
needed to start safely.
Dependencies installed?
- Node: check
node_modules/ exists
- Python: check virtualenv exists or key packages importable
- Ruby: check
bundle check passes
- Go/Rust/Java: no check needed (build tools handle it)
If missing, ask the user if you should install first. If the user or caller already
authorized setup and installation for this project, reuse that authorization.
3. Start with Monitor
Use the Monitor tool with persistent: true so the server runs for the session.
The grep filter matters because a raw dev-server stdout stream is mostly routine request logs — thousands of lines of noise that would flood the conversation and hide real errors. The pattern below surfaces only startup failures, runtime exceptions, build errors, and warnings:
<dev-command> 2>&1 | grep --line-buffered -iE \
'(error[:\[]| ERR[!_]|EADDRINUSE|EACCES|ENOENT|ECONNREFUSED|FATAL|panic|Segmentation|Module not found|Cannot find module|ModuleNotFoundError|ImportError|SyntaxError|TypeError|ReferenceError|NameError|AttributeError|KeyError|ValueError|RuntimeError|IndentationError|failed to|build failed|compile error|compilation error|WARN[:\[]|warning[:\[]|deprecated|port.*already|address already in use|unhandled|rejected|crash|killed|Traceback|Exception|FAILED|ActionView|ActiveRecord|LoadError|undefined method|NoMethodError|cannot find|not found|Permission denied|exit code [1-9]|exit status [1-9]|thread.*panic|cannot compile)'
Set the Monitor description to something specific: "Next.js dev :3000" or "Django dev :8000".
Port flag by stack (when user specifies a port):
- Next.js:
-p PORT
- Vite/Astro/SvelteKit/Nuxt/Remix/Angular:
--port PORT
- Django:
0.0.0.0:PORT
- Flask:
--port PORT
- FastAPI/Uvicorn:
--port PORT
- Rails:
-p PORT
- Phoenix: via
PORT=PORT env var
- Laravel:
--port PORT
- Go/Rust: usually via env var or arg (check the code)
Announce once started and verified:
Started Next.js dev server (bun run dev) on :3000 — root URL returned 200, no error overlay. Monitoring for errors.
3.5. Verify it's actually serving
"No error in the Monitor" ≠ "the app works." After the dev command announces readiness, confirm the server is reachable before handing control back to the user:
- HTTP probe —
curl -sS -o /dev/null -w "%{http_code}\n" http://localhost:<port> with a 5s timeout. Expect 2xx/3xx. Non-2xx, connection refused, or timeout → investigate.
- UI smoke check (frontend projects) — when a browser capability is available and
the project is a frontend framework (Next.js, Vite, Remix, Astro, SvelteKit, Nuxt,
Angular, Gatsby, Expo web), use it to load the root URL, take a screenshot, and check
for a visible error overlay. If the capability is unavailable, keep the HTTP probe,
record UI smoke as skipped with that reason, and do not claim the UI was verified.
- Backend-only projects — if there's a known health/root route (
/health, /api/health, /), curl it and show the status code. Otherwise one HTTP probe is enough.
If verification fails, surface it with the same classification as §4 (build/runtime/dependency/port) — don't just re-announce success.
4. React to errors
When a Monitor notification fires, surface everything the filter caught — do not silently drop items because they look minor. Claude's job is coverage; the user decides what to ignore.
- Classify — build error, runtime exception, missing dependency, port conflict, type error, syntax error, warning, deprecation.
- Context — quote the error, name the file and line if visible.
- Fix or ask — for obvious issues (missing dep, typo, known pattern), suggest or apply the fix. For ambiguous ones, ask.
- Severity shape — label each item (error / warning / info) so the user can filter; do not pre-filter on their behalf.
5. Stopping
When the user says "stop", "kill it", "shut down", or similar, use the host's available
monitor/session stop operation and confirm the exact server is stopped. If no stop
capability is available, report that blocker instead of claiming it stopped.
Edge cases
- Monorepo: If
package.json has workspaces or there's a turbo.json/nx.json, ask which package. Or check for a root dev script.
- Multiple servers: Frontend + backend? Start each Monitor in the same turn (parallel Bash calls) with distinct descriptions like
"Rails API :3001" and "Vite web :5173". Don't serialize — they're independent.
- Docker Compose: If
docker-compose.yml exists alongside a framework, mention both options.
- Custom commands: If the user says "run
XYZ and watch it", skip detection — just run their command through the Monitor filter.
- Turbopack: If Next.js dev script includes
--turbo, preserve it.
Session continuity
The Monitor is persistent: true and outlives context compaction. If the conversation has been compacted and the user asks about the server, restate: framework, port, PID (from startup), and how long it's been running. Don't assume the user remembers which dev server was started.
1---2name: dev-server-23description: Start any project's dev server and monitor it for errors in real-time. Universal — works with Node.js (Next.js, Vite, Remix, Astro, SvelteKit, Nuxt, Angular, Gatsby, Expo), Python (Django, Flask, FastAPI, Uvicorn), Ruby (Rails, Sinatra), Go, Rust (Cargo), Java (Spring Boot, Gradle, Maven), PHP (Laravel, Symfony), Elixir (Phoenix), and Docker Compose. Auto-detects the stack and package manager from project files. Uses the Monitor tool to stream only errors, warnings, and crashes — not routine request logs. Use this skill whenever the user says "start dev server", "run dev", "start the app", "launch the server", "npm run dev", "cargo run", "python manage.py runserver", "rails server", "go run", or anything that implies starting a local development server. Also trigger when the user asks to "monitor the server", "watch the build", "check for errors while I work", or simply "dev".4---56# Dev Server — Start & Monitor78Start the project's dev server and watch its output for errors. The user says "start dev" and you handle detection, startup, and monitoring — they only hear from you when something breaks.910When a server supports a task, resolve `../setup/references/task-context.md` and record11the command, port, monitor/session identifier and verification result there. A standalone12server start uses session state only and does not create a task.1314## Workflow1516### 1. Detect the stack1718Scan the working directory for project markers. Check in this order — first match wins:1920| Marker file | Stack | Dev command | Default port |21|---|---|---|---|22| `package.json` | Node.js (see framework table) | varies | 3000 |23| `manage.py` | Django | `python manage.py runserver` | 8000 |24| `Pipfile` or `pyproject.toml` with `[tool.poetry]` | Python (check for framework) | varies | 8000 |25| `requirements.txt` with `fastapi` | FastAPI | `uvicorn main:app --reload` | 8000 |26| `requirements.txt` with `flask` | Flask | `flask run --reload` | 5000 |27| `Gemfile` with `rails` | Rails | `bin/rails server` | 3000 |28| `Gemfile` with `sinatra` | Sinatra | `ruby app.rb` | 4567 |29| `go.mod` | Go | `go run .` | 8080 |30| `Cargo.toml` | Rust | `cargo run` | 8080 |31| `pom.xml` | Maven/Spring | `./mvnw spring-boot:run` | 8080 |32| `build.gradle` / `build.gradle.kts` | Gradle/Spring | `./gradlew bootRun` | 8080 |33| `mix.exs` with `phoenix` | Phoenix | `mix phx.server` | 4000 |34| `composer.json` with `laravel` | Laravel | `php artisan serve` | 8000 |35| `docker-compose.yml` | Docker | `docker compose up` | varies |36| `Makefile` with `dev` target | Make | `make dev` | varies |3738**Node.js framework detection** — when `package.json` exists, check dependencies:3940| Dependency | Framework | Default command |41|---|---|---|42| `next` | Next.js | `next dev` |43| `vite` or `@vitejs/*` | Vite | `vite` |44| `@remix-run/dev` | Remix | `remix dev` |45| `astro` | Astro | `astro dev` |46| `@sveltejs/kit` | SvelteKit | `vite dev` |47| `nuxt` | Nuxt | `nuxt dev` |48| `@angular/cli` | Angular | `ng serve` |49| `gatsby` | Gatsby | `gatsby develop` |50| `expo` | Expo | `expo start` |51| _(none match)_ | npm scripts | `<pm> run dev` | 3000 |5253**Node.js package manager** — check in order:541. `bun.lock` or `bun.lockb` → `bunx` / `bun run`552. `pnpm-lock.yaml` → `pnpm exec` / `pnpm run`563. `yarn.lock` → `yarn` / `yarn run`574. Default → `npx` / `npm run`5859**Python environment** — check in order:601. `.venv/` or `venv/` exists → `source .venv/bin/activate &&`612. `poetry.lock` → `poetry run`623. `Pipfile.lock` → `pipenv run`634. Default → direct command6465If nothing matches, tell the user you couldn't detect the stack and ask what command to run.6667If the detection picks a stack that seems wrong for the directory (e.g. `package.json` exists but it's just dev tooling in a Python project, or both `manage.py` and `package.json` present and unclear which is primary), show the user your guess and confirm before starting. Don't silently commit to a wrong stack.6869### 2. Pre-flight checks7071Before starting:72731. **Port conflict** — check if the default (or user-specified) port is taken:74 ```bash75 lsof -i :<port> -t 2>/dev/null76 ```77 If occupied, identify the occupying process (`ps -p <pid>`) and present two options to78 the user: kill PID N, or bind to port+1. Never kill a process without authorization. If79 the process is clearly another instance of this project, prefer port+1 when no choice is80 needed to start safely.81822. **Dependencies installed?**83 - Node: check `node_modules/` exists84 - Python: check virtualenv exists or key packages importable85 - Ruby: check `bundle check` passes86 - Go/Rust/Java: no check needed (build tools handle it)8788 If missing, ask the user if you should install first. If the user or caller already89 authorized setup and installation for this project, reuse that authorization.9091### 3. Start with Monitor9293Use the **Monitor** tool with `persistent: true` so the server runs for the session.9495The grep filter matters because a raw dev-server stdout stream is mostly routine request logs — thousands of lines of noise that would flood the conversation and hide real errors. The pattern below surfaces only startup failures, runtime exceptions, build errors, and warnings:9697```bash98<dev-command> 2>&1 | grep --line-buffered -iE \99 '(error[:\[]| ERR[!_]|EADDRINUSE|EACCES|ENOENT|ECONNREFUSED|FATAL|panic|Segmentation|Module not found|Cannot find module|ModuleNotFoundError|ImportError|SyntaxError|TypeError|ReferenceError|NameError|AttributeError|KeyError|ValueError|RuntimeError|IndentationError|failed to|build failed|compile error|compilation error|WARN[:\[]|warning[:\[]|deprecated|port.*already|address already in use|unhandled|rejected|crash|killed|Traceback|Exception|FAILED|ActionView|ActiveRecord|LoadError|undefined method|NoMethodError|cannot find|not found|Permission denied|exit code [1-9]|exit status [1-9]|thread.*panic|cannot compile)'100```101102Set the Monitor `description` to something specific: `"Next.js dev :3000"` or `"Django dev :8000"`.103104**Port flag by stack** (when user specifies a port):105- Next.js: `-p PORT`106- Vite/Astro/SvelteKit/Nuxt/Remix/Angular: `--port PORT`107- Django: `0.0.0.0:PORT`108- Flask: `--port PORT`109- FastAPI/Uvicorn: `--port PORT`110- Rails: `-p PORT`111- Phoenix: via `PORT=PORT` env var112- Laravel: `--port PORT`113- Go/Rust: usually via env var or arg (check the code)114115**Announce** once started *and* verified:116> Started **Next.js** dev server (`bun run dev`) on :3000 — root URL returned 200, no error overlay. Monitoring for errors.117118### 3.5. Verify it's actually serving119120"No error in the Monitor" ≠ "the app works." After the dev command announces readiness, confirm the server is reachable before handing control back to the user:1211221. **HTTP probe** — `curl -sS -o /dev/null -w "%{http_code}\n" http://localhost:<port>` with a 5s timeout. Expect 2xx/3xx. Non-2xx, connection refused, or timeout → investigate.1232. **UI smoke check (frontend projects)** — when a browser capability is available and124the project is a frontend framework (Next.js, Vite, Remix, Astro, SvelteKit, Nuxt,125Angular, Gatsby, Expo web), use it to load the root URL, take a screenshot, and check126for a visible error overlay. If the capability is unavailable, keep the HTTP probe,127record UI smoke as skipped with that reason, and do not claim the UI was verified.1283. **Backend-only projects** — if there's a known health/root route (`/health`, `/api/health`, `/`), `curl` it and show the status code. Otherwise one HTTP probe is enough.129130If verification fails, surface it with the same classification as §4 (build/runtime/dependency/port) — don't just re-announce success.131132### 4. React to errors133134When a Monitor notification fires, surface *everything* the filter caught — do not silently drop items because they look minor. Claude's job is coverage; the user decides what to ignore.1351361. **Classify** — build error, runtime exception, missing dependency, port conflict, type error, syntax error, warning, deprecation.1372. **Context** — quote the error, name the file and line if visible.1383. **Fix or ask** — for obvious issues (missing dep, typo, known pattern), suggest or apply the fix. For ambiguous ones, ask.1394. **Severity shape** — label each item (error / warning / info) so the user can filter; do not pre-filter on their behalf.140141### 5. Stopping142143When the user says "stop", "kill it", "shut down", or similar, use the host's available144monitor/session stop operation and confirm the exact server is stopped. If no stop145capability is available, report that blocker instead of claiming it stopped.146147## Edge cases148149- **Monorepo**: If `package.json` has `workspaces` or there's a `turbo.json`/`nx.json`, ask which package. Or check for a root `dev` script.150- **Multiple servers**: Frontend + backend? Start each Monitor in the **same turn** (parallel Bash calls) with distinct descriptions like `"Rails API :3001"` and `"Vite web :5173"`. Don't serialize — they're independent.151- **Docker Compose**: If `docker-compose.yml` exists alongside a framework, mention both options.152- **Custom commands**: If the user says "run `XYZ` and watch it", skip detection — just run their command through the Monitor filter.153- **Turbopack**: If Next.js dev script includes `--turbo`, preserve it.154155## Session continuity156157The Monitor is `persistent: true` and outlives context compaction. If the conversation has been compacted and the user asks about the server, restate: framework, port, PID (from startup), and how long it's been running. Don't assume the user remembers which dev server was started.