Quick commands & terminal
They arrive with the project
You rarely start from an empty list. XTop reads the project's own manifest files and offers what it finds as ready-made commands, so an imported project turns up with npm run dev already in its menu instead of a blank list you have to retype from memory.
Where they are read from
| File in the project | What becomes a command |
|---|---|
package.json | every entry under scripts, minus npm's own lifecycle hooks (postinstall, prepare, …) |
composer.json | every entry under scripts, minus composer's pre- / post- hooks |
artisan | php artisan serve and php artisan migrate |
Makefile | every target |
pyproject.toml | the entry points under [project.scripts] or [tool.poetry.scripts] — or, if there are none, install and test |
go.mod | go run ., go build ./..., go test ./... |
Cargo.toml | cargo run, cargo build, cargo test |
docker-compose.yml (or compose.yaml) | compose up, compose down, compose logs |
The runner matches your lockfile. A package.json script becomes pnpm dev when there is a pnpm-lock.yaml, yarn dev for yarn.lock, bun run dev for a bun lockfile, and npm run dev otherwise. A packageManager field beats all of them, because corepack enforces it anyway. Python works the same way: uv run with a uv.lock, poetry run with poetry.
Every detected command is tagged with the file it came from, so a list holding both npm run test and make test still tells you which is which.
Where you are asked, and where you are not
- Importing a folder — Add the commands found in each project is ticked by default, and the scan shows a count next to each project. Everything found is added.
- Adding or editing a single project — the list appears in the dialog with everything ticked, and you untick what you don't want.
- Any time later — Detect commands inside Manage commands… re-reads the project.
Detection never duplicates. A command whose line already exists on the project is skipped, so running it again on a project you imported months ago adds only the scripts that have appeared since.
Detected commands land in the private scope and run in the project's default location. Both are editable afterwards, like any other command.
Reading, not running
Detection only reads files — nothing in the project is executed. A package.json with a trailing comma, or a Makefile written for GNU extensions, simply contributes nothing and the other files are still read. At most 40 commands are taken from one project.
Three scopes
A command belongs to exactly one of three scopes, and the scope decides where it shows up:
| Scope | Offered in | Stored on |
|---|---|---|
| Private | one project | that project |
| Collection | every project in that collection | the collection |
| Global | every project | once, at the top level |
Global commands are stored once rather than copied into every project, so editing npm install updates it everywhere at the same time.

Manage them per project with ⌘ → Manage commands…, or for a whole collection with the ⌘ button in the collection header.
Each command has a label (what you see), the command line itself, and where to run it: the project's default, PowerShell, cmd, Git Bash, WSL, or an external terminal window.
Running one
Clicking a command opens the terminal window and starts a session.

- A tab per session. Switching tabs does not lose anything — each session keeps its own scrollback.
- The dot is the state. Green while the process is running, grey once it has exited.
- ■ Stop kills the running command; the tab and its output stay.
The shell follows the project's environment: wsl.exe -d <distro> --cd <path> for WSL projects, PowerShell for Windows ones.
Real sessions
These are interactive terminals, not log windows: you can answer a prompt, hit Ctrl+C, run vim if you insist.
On the rare machine where the interactive backend cannot load, the app falls back to streaming output with no keyboard input — and the terminal window says so in a banner, rather than leaving you wondering why typing does nothing.
Keys inside the terminal
| Key | Action |
|---|---|
| Ctrl+C | Copies when text is selected; with no selection it goes through as SIGINT, which is what the key is mostly pressed for |
| Ctrl+Shift+C | Always copies |
| Ctrl+V | Paste |
| Ctrl+click a URL | Open it in the browser. The modifier is deliberate — dragging a selection across a link should never launch a browser |
