Join us on discord @ discord.gg/mterm
mterm is a cross-platform command-line terminal that proxies the underlying command-line interpreters, such as powershell, sh or wsl. commands are executed in the background and results streamed to the foreground.
this means commands such as ls
, cd
or program commands such as node -v
or yarn install
will work out of the box as long as the host machine supports these commands. you can configure the desired interpreter below
- by no means does mterm replace your sh, or pwsh but we think abstractions such as secrets, and commands can supplement your development routines
- in other words, instead of building a utility for a dev task in a shell script for local use, use typescript
- mterm comes with tabs but also within the scope of a tab; each command is ran in the background - this means you can use your keyboard to hop around execution stacks
- output for commands do not stay in the terminal when you work on a new command. this new workflow considers the last execution while typing your next - but expects you to be in control of what you want to see (you'll have to see this to understand)
Head over to the release page to find the binary for your system type. mterm is evergreen and updates are automatically installed on your system as hey get released. Run :v
to see your current mterm version.
mterm is customizable in a few ways -
- add your own commands to the terminal
- quick add a command with
:cmd command_name
and edit this
- quick add a command with
- add extensions to the terminal
- quick add an extension with
ext add mterm-red
, see extensions for more info - make your own extensions, see mterm-ext-template for a starting point
- quick add an extension with
- change the theme of the terminal
- quick change the theme with
:theme
or:css
- quick change the theme with
- change the settings of the terminal
- quick change the settings with
:settings edit
- quick change the settings with
- change the profile of the terminal to a desired interpreter
- quick change the profile with
:settings set defaultProfile wsl
(change wsl with the desired profile)
- quick change the profile with
mterm_ext.mp4
Start typing, mterm will pick up your available: programs, system commands, custom commands and history
Finally, hit tab to finish the completion -
By default, mterm opens in command mode (you can change this in settings). A couple of notes about command mode -
- This window is always on top
- This window follows to any desktop
- The font and theme is larger to account for large size
This is a nice way to focus on execution details but it can be annoying if multiple windows are in use.
Hide mterm with the default toggle hotkey -
~ + CommandOrControl
Disable command mode and go to normal terminal window mode with -
~ + Shift + CommandOrControl
Or change the behaviour of all of this with settings.
mterm creates the mterm
folder on a host machine on first launch a the user's home directory
for windows -
C:/Users/<YOUR_NAME>/mterm
for mac -
/Users/<YOUR_NAME>/mterm
for everything else -
/home/<YOUR_NAME>/mterm
in this folder, there are a couple of important files to help configure mterm -
commands.ts
, used to attach commands to the terminal. see commandspackage.json
, an npm package declaration for use by commandstheme.css
, default theme used by the terminal, change this path/file with thetheme
property for profilessettings.json
, general runtime settings settings
here is an example ~/mterm/settings.json
-
{
"defaultProfile": "wsl",
"profiles": {
"powershell": {
"platform": "C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -noprofile -command $ARGS",
"theme": "theme.css",
"icon": "default"
},
"wsl": {
"platform": "bash -c $ARGS",
"theme": "theme.css",
"icon": "default"
}
},
"runner": {
"shortcut": "`+CommandOrControl",
"bounds": {
"screen": "PRIMARY",
"x": "SCREEN:-.5",
"y": "SCREEN:-.5",
"w": 720,
"h": 500
},
"commanderModeShortcut": "`+Shift+CommandOrControl",
"commanderMode": true,
"commanderModeBounds": {
"screen": 0,
"x": 0,
"y": "SCREEN:-.5",
"w": "SCREEN",
"h": 500
}
}
}
- default profile: the desired platform to execute commands against
- profiles: a list of profiles in the terminal
- runner
- shortcut: the global hotkey to toggle the runner
- bounds: the location of the terminal
- screen:
PRIMARY | number
, use the primary monitor or use the desired screen # - x, y, w, h:
SCREEN:ratio | number
use a ratio of the screen size (for centering etc) or use a static number
- screen:
- commandModeShorcut: the hotkey to toggle command mode
- commandMode: should mterm start by default in command mode?
- commanderModeBounds: the location of the terminal in command mode
- screen:
PRIMARY | number
, use the primary monitor or use the desired screen # - x, y, w, h:
SCREEN:ratio | number
use a ratio of the screen size (for centering etc) or use a static number
- screen:
mterm provided a few system commands to help control the terminal and settings. mterm settings will always start with :
(a colon) unless the intention is to override a system command. for example, because clear
needs to be handled in a special way for mterm windows + tabs, it is overriden in mterm.
Command | Alias | Purpose |
---|---|---|
clear |
cls |
Clear the current terminal output |
cd |
Navigate the file tree on the host machine | |
:exit |
exit |
Exit the current tab, or mterm if only 1 tab is open |
:edit |
edit |
Open the in-terminal editor with the file provided. Hit Ctrl+S to save in the editor |
:history |
Print out terminal history for debugging in a JSON format | |
:reload |
Reload settings, the ui, and commands without restarting | |
:tab |
Open a new tab | |
:test |
Sample command that executes after 10 seconds. Helpful for debugging | |
:vault |
Open the secret management tool, the mterm vault | |
:version |
:v |
Print the current mterm version |
:workspace |
Open the mterm workspace folder on disk: ~/mterm |
|
:theme |
:css |
Edit the terminal theme real time |
:cmd |
:commands |
Edit the command file |
:ext |
ext |
List terminal extensions |
:ext add {extenstion} |
Add the extension, see extension | |
:ext rm {extenstion} |
Remove the extension, see extension | |
:cmd {cmd_name} |
Edit the command file for the cmd_name, creates if this doesn't exist | |
:settings |
Open the mterm settings gui to manage ~/mterm/settings.json |
|
:settings edit |
Open the ~/mterm/settings.json in the terminal editor with hot reloading |
|
:settings reload |
Reload ~/mterm/settings.json and all ui etc associated with the settings |
|
:settings {get|set} {key} |
Set the setting key matching the path in ~/mterm/settings.json and reload |
Need your own command? MTERM includes ~/mterm/commands.ts
from your home directory - with any exported functions as available commands.
Here an example -
import * as os from 'node:os'
export function hello(name: string = os.userInfo().username): string {
return `Hi, ${name}`
}
Now run hello X
from mterm -
In this case, no argument was provided so the
os.userInfo().username
was the fallback.Hello, DR
is the result!
Note: commands are in snake case always when running. helloWorld
will be hello_world
when running in mterm. however, mterm will still resolve helloWorld
as hello_world
when running - it's just important to note this when dealing with name collisions. every command is stored in snake case.
add a command to and edit this command -
:cmd command_name
command_name
is now available to mterm (or commandName
or COMMAND_NAME
- note all names are resolved to snake_case
)
in the same fasion you add a command, edit a command with the same syntax -
:cmd command_name
this editor will save with Ctrl+S
and reload the command every time you save.
Try fetching data!
export async function query(): Promise<{
userId: number
id: number
title: string
completed: boolean
}> {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1')
return await response.json()
}
Note the return type is optional, just added above to highlight the typescript engine provided
Shell (https://www.electronjs.org/docs/latest/api/shell) is provided within the command context, use shell like this:
to open folder or file:
await this.shell.openPath(path)
to open URL:
await this.shell.openExternal(path)
to open editor
await shell.openPath(
${editorCommand} ${filePath})
Sometimes we need to change variables, execution results or perform an operation on strings.
MTERM helps solve this by providing transformers
as terminal operators. These transformers abstract away somewhat tedious actions in the terminal, they also provide common utilities within the scope of a prompt
For the prompt of
":snake(this is some text)"
We get the result
this_is_some_text
snake
is a mterm transformer that takes a string and converts it to snake case
Transformers can be used anywhere including from within transformers -
":upper(hmm) :lower(WOW) :snake(:lower(HMM WOW))"
Prints out -
HMM wow hmm_wow
Some transformers accept arguments. Arguments for transformers are seperated by :
colon characters
Here is the split transformer on a string -
":split(1,2,3,4:1:,)"
1,2,3,4
is the first argument, the split text1
is the index to return (a split operation is an array, so return a value from this array),
the final argument is the delimiter
one way to view this operation is
"1,2,3,4".split(',')[1]
Note you can use "
quotes to wrap transformer arguments if there is a colon within the argument
Here are the provided transformers for use -
print out the argument, proxies the argument to the
echo
on the terminal
:echo
examples -
:echo(HELLO) -> "HELLO"
:echo(:upper(hello)) -> "HELLO"
gets the argument from the vault, if not available gets the argument from the environment variables from the host machine, if not available returns the fallback
:get
examples -
# e.g: Basic find
#
# assuming:
## there is a env variable called PATH=PATH_FROM_SYSTEM
:get(PATH) -> "PATH_FROM_SYSTEM"
# e.g: Fallback keys
#
# assuming:
## there is NOT a env variable called NOT_FOUND_A
## there is NOT a env variable called NOT_FOUND_B
## there is a env variable called FOUND_C=VALUE_OF_C
:get(NOT_FOUND_A,NOT_FOUND_B,FOUND_C) -> "VALUE_OF_C"
# e.g: Fallback variable
#
# assuming:
## there is NOT a env variable called NOT_FOUND_A
## there is a env variable called FOUND_C=VALUE_OF_C
:get(NOT_FOUND_A:im the fallback) -> "im the fallback"
:get(FOUND_C:im the fallback) -> "VALUE_OF_C"
transforms the argument to lowercase
:lower
examples -
":lower(HELLO)" -> "hello"
:echo(:lower(HELLO)) -> "hello"
runs the argument against the terminal and proxies the result
:run
examples -
# e.g: Run command
#
# assuming:
# there is a `hello` function in `commands.ts`
# the `hello` function is declared as const hello = (arg = 'fallback') => `Hello, ${arg}!`
":run(hello)" -> "Hello, fallback!"
":run(hello argument)" -> "Hello, argument!"
# e.g: Run command within transformer
#
# assuming:
# there is a `hello` function in `commands.ts`
# the `hello` function is declared as const hello = (arg = 'fallback') => `Hello, ${arg}!`
":lower(:run(hello))" -> "hello, fallback!"
":lower(:run(hello)) :upper(:run(hello))" -> "hello, fallback! HELLO, FALLBACK!"
transforms the argument to snakecase
:snake
examples -
":snake(HELLO WORLD)" -> "hello_world"
transforms the argument to titlecase
:title
examples -
":title(hello world)" -> "Hello World"
":title(hello_world)" -> "Hello World"
splits the provided argument, accepts the index or uses
0
, accepts the delimiter or uses,
:split
examples -
":split(hello,world)" -> "hello"
":split(hello,world:1)" -> "world"
":split(hello@world:1:@)" -> "world"
:echo(":split(":get(xx,PATH)":0:;)") -> "FIRST_RESULT_IN_PATH"
transforms the argument to uppercase
:title
examples -
":uppercase(hello world)" -> "HELLO WORLD"
Environment variables are a bit unsafe. You set these and leave the host machine all the ability to read and share these. Wonderful for services and backends, not the safest for personal usage.
While mterm
does support reading env variables in the terminal, an alternative much safer secret mechanism is provided.
Passwords, URLS (any value really) can be stored in the vault -
Open the vault wih
:vault
or use the tray icon openVault and Secrets
The mterm vault is an AES-256
encrypted store on your local machine. During setup, you provide a password for this store.
Every time mterm
is launched, the password is required to use these values provided. You can find vault values by using this.vault.get
in commands -
export function who() {
const name = this.vault.get('NAME')
return `name: ${name}`
}
mterm provides an editor with :edit <FILE>
or edit <FILE>
commands -
hit control + s
within the file editor to save this
When you change the tab name to include $idx
- this will be replaced with the current tab index
You can install packages in the ~/mterm
folder and use them in commands.ts
see local setup for code setup info.
ensure editor has prettier settings configured for .pretierrc.yaml
or PRs will fail.
every commit must be in conventional commit format. this is how we auto generate release notes and change logs. features might be ignored if this rule is not followed.
make sure to make a pr with this format: feature/<name_or_issue_number>
.
reach out on discord for contributor role.
note: quickly install yarn on node 20+ with
corepack enable
clone -
git clone git@github.com:mterm-io/mterm.git
install deps -
yarn
run locally -
$ yarn dev
note, because these require github token during build - this will probably fail for you. adding here either way for completeness
# For windows
yarn build:win
# For macOS
yarn build:mac
# For Linux
yarn build:linux