---
name: run
description: Launch and drive this project's app to see a change working. Use when asked to run, start, or screenshot the app, or to confirm a change works in the real app (not just tests). First looks for a project-provided launch recipe; otherwise falls back to built-in patterns per project type (CLI, server, TUI, desktop GUI, browser-driven, library).
---

**Running means launching the actual app and interacting with it** —
not the test suite, not an `import` of an internal function and a
`console.log`. The app as a user (human or programmatic) would meet
it: the CLI at its command, the server at its socket, the GUI at its
window.

## First: does a project recipe already cover this?

A project-provided recipe that launches this app is the repo's
verified path — its author already cold-started and committed what
worked: the exact install line, the env vars, the patches, the
driver. Use it instead of rediscovering. Look in, roughly in order:

- your available skills (a launch/verify recipe for this project or
  this kind of app);
- the repo's own entry points: README "getting started", Makefile /
  justfile targets, package.json scripts, docker-compose files,
  CI workflow steps that boot the app.

- **One describes launching/driving this app** → follow it verbatim.
  Don't paraphrase; don't skip the patches.
- **Mega-repo, several plausible, no clear match** → ask the user
  which unit to run.
- **Stale** (fails on mechanics unrelated to your task) → tell the
  user; offer to refresh it.
- **Nothing about running** → fall back to the patterns below.

## Otherwise: match the shape, use the pattern

Pick the row closest to your project.

| Project type | Handle | Pattern |
|---|---|---|
| CLI tool | direct invocation, exit code, stdin/stdout | invoke it below |
| Web server / API | background launch + `curl` smoke | lifecycle below |
| TUI / interactive terminal | tmux `send-keys` / `capture-pane` | tmux pattern below |
| Desktop GUI | drive it headless (xvfb + an automation driver), screenshot | adapt the browser pattern |
| Browser-driven web app | dev server + headless browser script | browser pattern below |
| Library / SDK | import-and-call smoke script at the package boundary | library pattern below |

If nothing fits, start from the closest match and adapt.

### CLI

No lifecycle, no ports. Get the binary runnable (build, or install in
editable/dev mode so it lands on PATH), confirm with `--version` or
`--help`, then run a representative command and check exit code and
output:

```bash
mytool process input.json
# → Processed 42 records, wrote output.json
echo $?   # meaningful exit codes are part of the interface
```

If the tool reads stdin, pipe test data in.

### Web server / API

Start in the background with logs captured, poll for readiness (never
a fixed sleep), then hit the routes:

```bash
<start-command> &> /tmp/server.log &
SERVER_PID=$!
for i in {1..30}; do curl -sf localhost:PORT/health >/dev/null && break; sleep 1; done
curl -si localhost:PORT/api/thing      # status + headers + body
kill $SERVER_PID
```

No health endpoint? Poll the route you're about to test until it
stops returning connection-refused.

### TUI / interactive terminal app

Interactive terminal apps (editors, REPLs, curses UIs) take over the
terminal — you can't drive them directly from a shell tool. Wrap them
in tmux: start detached, send keystrokes, capture the pane, kill the
session when done.

```bash
tmux new-session -d -s app -x 120 -y 40 './myapp'

# poll until the ready marker appears (fails loudly if it never does)
timeout 10 bash -c 'until tmux capture-pane -t app -p | grep -q "Ready"; do sleep 0.2; done'
tmux capture-pane -t app -p

# send input and wait for the screen to reflect it
tmux send-keys -t app 's'
timeout 5 bash -c 'until tmux capture-pane -t app -p | grep -q "Settings"; do sleep 0.2; done'
tmux send-keys -t app 'Down' 'Down' 'Space'
tmux capture-pane -t app -p

# quit
tmux send-keys -t app 'q'
tmux kill-session -t app 2>/dev/null || true
```

Details that matter: pick a known-good terminal size (`-x`/`-y` —
some TUIs break at small widths); poll for a ready string rather than
sleeping; learn the app's keybindings (they're its API); always
`kill-session` as a fallback exit. If `capture-pane` output is hard
to read, `-e` keeps escape sequences and `-J` joins wrapped lines.
Use a private socket (`tmux -L name`) so you don't collide with other
sessions on the box.

### Browser-driven web app

Start the dev server (background + readiness poll, as above), then
drive the page with a headless browser script (e.g. Playwright):
navigate, click the flow the change touches, screenshot. **Look at
the screenshot** — a blank frame is a failure to launch, not a pass.

### Library / SDK

There's no process to start. "Running" it is: build from source, then
a minimal smoke program that imports the library **through its public
package boundary** and does one real thing:

```bash
python -c '
from mylib import Client
print(Client().ping())
'
# → pong
```

## Drive it, don't just launch it

Launching with no interaction proves the entrypoint resolves. That's
not running the app — it's typechecking with extra steps. Drive it to
a point where a user would see something:

- CLI → type a representative command, check the exit code and output.
- Server → hit the route the diff touches with `curl`, read the body.
- TUI → `send-keys` a navigation, `capture-pane` the result.
- GUI → click the button, screenshot the window. **Look at the
  screenshot.** A blank frame is a failure to launch.

If the fallback pattern didn't work out of the box — you had to
install packages, set env vars, patch config, or write a driver —
record the exact recipe that worked in your report so it can be
captured as a project skill. If it just worked, don't.
