base on Run multiple commands in parallel <div align="center" markdown="1"> <sup>Special thanks to:</sup> <br> <a href="https://go.warp.dev/mprocs"> <img alt="Warp sponsorship" width="400" src="https://github.com/warpdotdev/brand-assets/blob/main/Github/Sponsor/Warp-Github-LG-02.png"> </a> ### [Warp, built for coding with multiple AI agents](https://go.warp.dev/mprocs) [Available for MacOS, Linux, & Windows](https://go.warp.dev/mprocs)<br> </div> # mprocs _mprocs_ runs multiple commands in parallel and shows output of each command separately. When you work on a project you very often need the same list of commands to be running. For example: `webpack serve`, `jest --watch`, `node src/server.js`. With mprocs you can list these command in `mprocs.yaml` and run all of them by running `mprocs`. Then you can switch between outputs of running commands and interact with them. It is similar to [concurrently](https://github.com/open-cli-tools/concurrently) but _mprocs_ shows output of each command separately and allows to interact with processes (you can even work in _vim_ inside _mprocs_). <!--ts--> - [Screenshots](#screenshots) - [Installation](#installation) - [Download binary (Linux, Macos, Windows)](#download-binary-linux-macos-windows) - [npm (Linux, Macos, Windows)](#npm-linux-macos-windows) - [homebrew (Macos)](#homebrew-macos) - [cargo (All platforms)](#cargo-all-platforms) - [scoop (Windows)](#scoop-windows) - [AUR (Arch Linux)](#aur-arch-linux) - [MPR (Debian/Ubuntu)](#mpr-debianubuntu) - [Usage](#usage) - [Config](#config) - [Keymap](#keymap) - [$select operator](#select-operator) - [Running scripts from package.json](#running-scripts-from-packagejson) - [Default keymap](#default-keymap) - [Remote control](#remote-control) - [FAQ](#faq) - [mprocs vs tmux/screen](#mprocs-vs-tmuxscreen) <!-- Created by https://github.com/ekalinin/github-markdown-toc --> <!-- Added by: pvolok, at: Sun Jul 3 22:53:57 +07 2022 --> <!--te--> ## Screenshots <img src="img/screenshot1.png" width="900" height="645" /> <img src="img/screenshot2.png" width="900" height="645" /> ## Installation [![Packaging status](https://repology.org/badge/vertical-allrepos/mprocs.svg)](https://repology.org/project/mprocs/versions) ### Download binary (Linux, Macos, Windows) [Download](https://github.com/pvolok/mprocs/releases) executable for your platform and put it into a directory included in PATH. ### npm (Linux, Macos, Windows) ```sh npm install -g mprocs ``` ```sh yarn global add mprocs ``` ### homebrew (Macos, Linux) ```sh brew install mprocs ``` ### cargo (All platforms) ```sh cargo install mprocs ``` ### scoop (Windows) ```sh scoop install mprocs ``` ### AUR (Arch Linux) ```sh yay mprocs ``` ```sh yay mprocs-bin ``` ### MPR (Debian/Ubuntu) ```sh git clone 'https://mpr.makedeb.org/mprocs' cd mprocs/ makedeb -si ``` ## Usage 1. Run `mprocs cmd1 cmd2 …` (example: `mprocs "yarn test -w" "webpack serve"`) OR 1. Create `mprocs.yaml` file 2. Run `mprocs` command Example `mprocs.yaml`: ```yaml procs: nvim: cmd: ["nvim"] server: shell: "nodemon server.js" webpack: "webpack serve" tests: shell: "jest -w" env: NODE_ENV: test ``` ### Config [JSON/YAML Configuration Schema](https://json.schemastore.org/mprocs-0.6.4.json) There are two kinds of configs: global and local. _Global_ config is loaded from `~/.config/mprocs/mprocs.yaml` (or `~\AppData\Roaming\mprocs\mprocs.yaml` on Windows). _Local_ config is loaded from `mprocs.yaml` from current directory (or set via cli argument: `mprocs --config ./cfg/mprocs.yaml`). Settings in the _local_ config override settings in the _global_ config. - **procs**: _object_ - Processes to run. Only allowed in local config. - **shell**: _string_ - Shell command to run (exactly one of **shell** or **cmd** must be provided). - **cmd**: _array<string>_ - Array of command and args to run (exactly one of **shell** or **cmd** must be provided). - **cwd**: _string_ - Set working directory for the process. Prefix `<CONFIG_DIR>` will be replaced with the path of the directory where the config is located. - **env**: _object<string, string|null>_ - Set env variables. Object keys are variable names. Assign variable to null, to clear variables inherited from parent process. - **add_path**: _string|array<string>_ - Add entries to the _PATH_ environment variable. - **autostart**: _bool_ - Start process when mprocs starts. Default: _true_. - **autorestart**: _bool_ - Restart process when it exits. Default: false. Note: If process exits within 1 second of starting, it will not be restarted. - **stop**: _"SIGINT"|"SIGTERM"|"SIGKILL"|{send-keys: array<key>}|"hard-kill"_ - A way to stop a process (using `x` key or when quitting mprocs). - **hide_keymap_window**: _bool_ - Hide the pane at the bottom of the screen showing key bindings. - **mouse_scroll_speed**: _integer_ - Number of lines to scrollper one mouse scroll. - **scrollback**: _integer_ - Scrollback size. Default: _1000_. - **proc_list_width**: _integer_ - Process list window width. - **keymap_procs**: _object_ - Key bindings for process list. See [Keymap](#keymap). - **keymap_term**: _object_ - Key bindings for terminal window. See [Keymap](#keymap). - **keymap_copy**: _object_ - Key bindings for copy mode. See [Keymap](#keymap). #### Keymap Default key bindings can be overridden in config using _keymap_procs_, _keymap_term_, or _keymap_copy_ fields. Available commands are documented in the [Remote control](#remote-control) section. There are three keymap levels: - Default keymaps - `~/.config/mprocs/mprocs.yaml` (or `~\AppData\Roaming\mprocs\mprocs.yaml` on Windows) - `./mprocs.yaml` (can be overridden by the _-c/--config_ cli arg) Lower levels override bindings from previous levels. Key bindings from previous levels can be cleared by specifying `reset: true` field at the same level as keys. Key bindings are defined between `<` and `>`, e.g., `<Enter>` (enter key), `<Down>` (down arrow), `<Up>` (up arrow), `<C-q>` (CTRL + q). ```yaml keymap_procs: # keymap when process list is focused <C-q>: { c: toggle-focus } <C-a>: null # unbind key keymap_term: # keymap when terminal is focused reset: true <C-q>: { c: toggle-focus } <C-j>: c: batch cmds: - { c: focus-procs } - { c: next-proc } ``` #### `$select` operator You can define different values depending on the current operating system. Any value in config can be wrapped with a _$select_ operator. To provide different values based on current OS define an object with: - First field `$select: os` - Fields defining values for different OSes: `macos: value`. Possible values are listed here: https://doc.rust-lang.org/std/env/consts/constant.OS.html. - Field `$else: default value` will be matched if no value was defined for current OS. If current OS is not matched and field `$else` is missing, then mprocs will fail to load config. Example `mprocs.yaml`: ```yaml procs: my process: shell: $select: os windows: "echo %TEXT%" $else: "echo $TEXT" env: TEXT: $select: os windows: Windows linux: Linux macos: Macos freebsd: FreeBSD ``` #### Running scripts from package.json If you run _mprocs_ with an `--npm` argument, it will load scripts from `package.json`. But the scripts are not run by default, and you can launch desired scripts manually. ```sh # Run mprocs with scripts from package.json mprocs --npm ``` ### Default keymap Process list focused: - `q` - Quit (soft kill processes and wait then to exit) - `Q` - Force quit (terminate processes) - `C-a` - Focus output pane - `x` - Soft kill selected process (send SIGTERM signal, hard kill on Windows) - `X` - Hard kill selected process (send SIGKILL) - `s` - Start selected process, if it is not running - `r` - Soft kill selected process and restart it when it stops - `R` - Hard kill selected process and restart it when it stops - `a` - Add new process - `C` - Duplicate selected process - `d` - Remove selected process (process must be stopped first) - `e` - Rename selected process - `k` or `↑` - Select previous process - `j` or `↓` - Select next process - `M-1` - `M-8` - Select process 1-8 - `C-d` or `page down` - Scroll output down - `C-u` or `page up` - Scroll output up - `C-e` - Scroll output down by 3 lines - `C-y` - Scroll output up by 3 lines - `z` - Zoom into terminal window - `v` - Enter copy mode Process output focused: - `C-a` - Focus processes pane Copy mode: - `v` - Start selecting end point - `c` - Copy selected text - `Esc` - Leave copy mode - `C-a` - Focus processes pane - `C-d` or `page down` - Scroll output down - `C-u` or `page up` - Scroll output up - `C-e` - Scroll output down by 3 lines - `C-y` - Scroll output up by 3 lines - `k` or `↑` - Move cursor up - `l` or `→` - Move cursor right - `j` or `↓` - Move cursor down - `h` or `←` - Move cursor left ### Remote control Optionally, _mprocs_ can listen on TCP port for remote commands. You have to define remote control server address in `mprocs.yaml` (`server: 127.0.0.1:4050`) or via cli argument (`mprocs --server 127.0.0.1:4050`). To send a command to running _mprocs_ instance use the **ctl** argument: `mprocs --ctl '{c: quit}'` or `mprocs --ctl '{c: send-key, key: <C-c>}'`. Commands are encoded as yaml. Available commands: - `{c: quit-or-ask}` - Stop processes and quit. If any processes are running, show a confirmation dialog. - `{c: quit}` - Stop processes and quit. Does not show confirm dialog. - `{c: force-quit}` - `{c: toggle-focus}` - Toggle focus between process list and terminal. - `{c: focus-procs}` - Focus process list - `{c: focus-term}` - Focus process terminal window - `{c: zoom}` - Zoom into terminal window - `{c: next-proc}` - `{c: prev-proc}` - `{c: select-proc, index: <PROCESS INDEX>}` - Select process by index, top process has index 0 - `{c: start-proc}` - `{c: term-proc}` - `{c: kill-proc}` - `{c: restart-proc}` - Restart selected process - `{c: restart-all}` - Restart all processes - `{c: force-restart-proc}` - Restart selected process by sending SIGKILL - `{c: force-restart-all}` - `{c: show-add-proc}` - `{c: add-proc, cmd: "<SHELL COMMAND>", name: "<PROC NAME>"}` - Add proccess. `name` field is optional. - `{c: duplicate-proc}` - `{c: show-remove-proc}` - `{c: remove-proc, id: "<PROCESS ID>"}` - `{c: show-rename-proc}` - `{c: rename-proc, name: "<NEW_NAME>"}` - Rename currently selected process - `{c: scroll-down}` - `{c: scroll-up}` - `{c: scroll-down-lines, n: <COUNT>}` - `{c: scroll-up-lines, n: <COUNT>}` - `{c: copy-mode-enter}` - Enter copy mode - `{c: copy-mode-leave}` - Leave copy mode - `{c: copy-mode-move, dir: <DIRECTION> }` - Move starting or ending position of the selection. Available directions: `up/right/down/left`. - `{c: copy-mode-end}` - Start selecting end point of the selection. - `{c: copy-mode-copy}` - Copy selected text to the clipboard and leave copy mode. - `{c: send-key, key: "<KEY>"}` - Send key to current process. Key examples: `<C-a>`, `<Enter>` - `{c: batch, cmds: [{c: focus-procs}, …]}` - Send multiple commands ## FAQ ### mprocs vs tmux/screen _mprocs_ is meant to make it easier to run specific commands that you end up running repeatedly, such as compilers and test runners. This is in contrast with _tmux_, which is usually used to run much more long-lived processes - usually a shell - in each window/pane. Another difference is that _tmux_ runs a server and a client, which allows the client to detach and reattach later, keeping the processes running. _mprocs_ is meant more for finite lifetime processes that you keep re-running, but when _mprocs_ ends, so do the processes it is running within its windows. ### Copying doesn't work in tmux Tmux doesn't have escape sequences for copying enabled by default. To enable it add the following to `~/.tmux.conf`: ``` set -g set-clipboard on ``` ", Assign "at most 3 tags" to the expected json: {"id":"8563","tags":[]} "only from the tags list I provide: [{"id":77,"name":"3d"},{"id":89,"name":"agent"},{"id":17,"name":"ai"},{"id":54,"name":"algorithm"},{"id":24,"name":"api"},{"id":44,"name":"authentication"},{"id":3,"name":"aws"},{"id":27,"name":"backend"},{"id":60,"name":"benchmark"},{"id":72,"name":"best-practices"},{"id":39,"name":"bitcoin"},{"id":37,"name":"blockchain"},{"id":1,"name":"blog"},{"id":45,"name":"bundler"},{"id":58,"name":"cache"},{"id":21,"name":"chat"},{"id":49,"name":"cicd"},{"id":4,"name":"cli"},{"id":64,"name":"cloud-native"},{"id":48,"name":"cms"},{"id":61,"name":"compiler"},{"id":68,"name":"containerization"},{"id":92,"name":"crm"},{"id":34,"name":"data"},{"id":47,"name":"database"},{"id":8,"name":"declarative-gui "},{"id":9,"name":"deploy-tool"},{"id":53,"name":"desktop-app"},{"id":6,"name":"dev-exp-lib"},{"id":59,"name":"dev-tool"},{"id":13,"name":"ecommerce"},{"id":26,"name":"editor"},{"id":66,"name":"emulator"},{"id":62,"name":"filesystem"},{"id":80,"name":"finance"},{"id":15,"name":"firmware"},{"id":73,"name":"for-fun"},{"id":2,"name":"framework"},{"id":11,"name":"frontend"},{"id":22,"name":"game"},{"id":81,"name":"game-engine "},{"id":23,"name":"graphql"},{"id":84,"name":"gui"},{"id":91,"name":"http"},{"id":5,"name":"http-client"},{"id":51,"name":"iac"},{"id":30,"name":"ide"},{"id":78,"name":"iot"},{"id":40,"name":"json"},{"id":83,"name":"julian"},{"id":38,"name":"k8s"},{"id":31,"name":"language"},{"id":10,"name":"learning-resource"},{"id":33,"name":"lib"},{"id":41,"name":"linter"},{"id":28,"name":"lms"},{"id":16,"name":"logging"},{"id":76,"name":"low-code"},{"id":90,"name":"message-queue"},{"id":42,"name":"mobile-app"},{"id":18,"name":"monitoring"},{"id":36,"name":"networking"},{"id":7,"name":"node-version"},{"id":55,"name":"nosql"},{"id":57,"name":"observability"},{"id":46,"name":"orm"},{"id":52,"name":"os"},{"id":14,"name":"parser"},{"id":74,"name":"react"},{"id":82,"name":"real-time"},{"id":56,"name":"robot"},{"id":65,"name":"runtime"},{"id":32,"name":"sdk"},{"id":71,"name":"search"},{"id":63,"name":"secrets"},{"id":25,"name":"security"},{"id":85,"name":"server"},{"id":86,"name":"serverless"},{"id":70,"name":"storage"},{"id":75,"name":"system-design"},{"id":79,"name":"terminal"},{"id":29,"name":"testing"},{"id":12,"name":"ui"},{"id":50,"name":"ux"},{"id":88,"name":"video"},{"id":20,"name":"web-app"},{"id":35,"name":"web-server"},{"id":43,"name":"webassembly"},{"id":69,"name":"workflow"},{"id":87,"name":"yaml"}]" returns me the "expected json"