cli.md RawHistoryFolder

CLI

The ermite binary also drives a running server over its API. Run ermite <command> --help for the details of each command.

Connect to a server

Setting Environment Config file key
server address ERMITE_URL url
token (optional for public reads) ERMITE_TOKEN token.cmd, a command that prints it

The environment wins over the config file.

ermite config set url https://git.example.com
ermite config set token.cmd 'pass show ermite/token'
ermite config show [--json]   # path and values
ermite config unset <key>

The file holds no secret, only the command that fetches the token (pass, gopass show -o, op read, secret-tool lookup, …):

# ~/.config/ermite/config
url       = https://git.example.com
token.cmd = pass show ermite/token

Location: $XDG_CONFIG_HOME/ermite/config, ~/Library/Application Support/ermite/config on macOS, %AppData%\ermite\config on Windows. ERMITE_CONFIG names another file.

A token sent over plain http:// to a non-loopback host prints a warning.

How token.cmd runs

  • Through sh -c (cmd /C on Windows), at most once per run, only when a command needs the token.
  • It gets your terminal when stdin is one, so pinentry or biometric prompts work.
  • It must print the token alone on one line, under 4 KiB, within 60 seconds. On timeout or interrupt it is killed.
  • A failure is reported in one line, without the command's output.

It does not run:

  • when ERMITE_TOKEN is set;
  • for ermite version, ermite config or shell completion;
  • when ERMITE_URL points to another server than the file's url (the call is anonymous; set ERMITE_TOKEN);
  • when the file or its directory is writable by other users, or owned by another user (not checked on Windows).

Commands

ermite repo list | show <name> | create <name> [--description …] [--visibility public]
ermite repo edit <name> [--description …] [--visibility …] [--default-branch …] [--merge-modes …] [--allow-auto-merge] [--issues off|owner|public]
ermite repo delete <name> [--yes]

ermite token create <label> [--preset cli|agent|ci|runner] [--scope …] [--repo …] [--branch-prefix …] [--expires 30d]
ermite token list | revoke <id>

ermite mr create <repo> --source <branch> --title … | list <repo> | show <repo> <n> [--diff]   # show prints the mergeability: up to date, behind, conflict
ermite mr comment <repo> <n> -m … [--path … --line N|A-B --side old|new] [--reply <id>] [--approve|--request-changes]
ermite mr resolve <repo> <n> <comment> | edit-comment <repo> <n> <comment> -m … | delete-comment <repo> <n> <comment>
ermite mr ready <repo> <n>                 # removes WIP:/[WIP], needs mr:write
ermite mr merge <repo> <n> --head <id> [--mode fast-forward|squash|merge] [--delete-branch] [--ignore-checks] | merge <repo> <n> --head <id> --auto [--mode …] | merge <repo> <n> --cancel-auto | close <repo> <n>

ermite issue create <repo> --title … [--body … | --body-file …] | list <repo> [--state open|closed|resolved|all]
ermite issue show <repo> <n> | comment <repo> <n> -m … | close <repo> <n> | resolve <repo> <n> | reopen <repo> <n>
# issue show prints `resolved by !N` when a merge resolved it, linked merge requests, and timestamped history interleaved with comments; --json adds closed_by_merge_request, references and events
# mr show lists linked issues (number, state, resolves marker) and their history; --json adds issues and issue_events

ermite run list <repo> [--workflow …] [--branch …] [--status …]
ermite run view <repo> <id> [--attempt n] [--log [--job …]] [--summary]
ermite run watch <repo> <id> [--log] | cancel <repo> <id> | rerun <repo> <id> [--failed]
ermite run artifacts <repo> <id> | download <repo> <id> [--name N]… [--dir D]
ermite workflow run <file> --repo <repo> [--ref …] [-f name=value …]
ermite workflow list <repo> [--json]
ermite workflow disable <repo> <file>    # no event starts a run of it; the file need not exist yet
ermite workflow enable <repo> <file>
ermite runner list | remove <id>
ermite secret set|list|delete …         # CI secrets (needs ERMITE_SECRETS_KEY)
ermite variable set|get|list|delete …
ermite environment create|list|delete … --repo <repo>

ermite mirror key show | rotate          # SSH key to add to the remote (rotate: owner only)
ermite mirror config [--enabled] [--url …{repo}…] [--cron …] [--all-branches] | config show   # global policy, owner only
ermite mirror add <repo> <url> [--cron …] [--all-branches] | remove <repo> | exclude <repo> | include <repo>
ermite mirror status [repo] | sync <repo>|--all [--force]   # sync --all: one row per repository, exit 1 if any failed

ermite web login                         # one-time sign-in link (60 s)
ermite web logout --all                  # sign every browser out
ermite web passkey list | remove <id>
ermite signing-key show                  # public key of squash and merge commits (server-signed)
ermite oidc rotate-key
ermite watch [repo] [--json]             # follow live events
ermite version                           # client and server versions
ermite completion bash|zsh|fish

Issues need a server with the issues feature and ermite repo edit <repo> --issues owner (or --issues public, which also opens a moderated form to visitors of a public repository); they are written with the issue:write scope. An issue is open, closed (not resolved), or resolved. issue resolve <repo> <n> marks an open issue fixed (issues.resolve feature); merging a request with Fixes #N resolves it too. issue reopen accepts closed and resolved issues. History records references, closing, reopening and resolution with the actor and timestamp; removed references keep their history. See Issues.

Mirrors push repositories to a remote over SSH, never forcing. See Push mirror.

Releases

Releases need a server advertising the releases feature. Published releases follow repository visibility; drafts are visible only to release writers. Writes need release:write (included in the cli token preset); branch-limited tokens cannot write releases. On an older server the preset drops this scope with a note, while an explicit --scope release:write fails before creating a token.

ermite release create <repo> <tag> [--title T] [--notes TEXT | --notes-file F] [--target REF] [--draft] [--prerelease] [--latest] [--asset FILE[#LABEL]]… [--json]
ermite release list <repo> [--limit N] [--json]
ermite release view <repo> <tag|id|latest> [--json | --notes]
ermite release edit <repo> <tag|id> [--title T] [--notes TEXT | --notes-file F] [--tag NEW] [--target REF] [--draft | --publish] [--prerelease | --no-prerelease] [--latest]
ermite release delete <repo> <tag|id> [--yes]
ermite release upload <repo> <tag|id> FILE[#LABEL]… [--clobber] [--content-type T]
ermite release download <repo> <tag|id|latest> [--pattern GLOB]… [--name N]… [--dir D]

All-digit selectors are release ids; other selectors are tags. latest selects the latest release for view/download. --latest pins a release as latest. Non-draft releases require an existing tag, or --target to create one; an existing tag is never moved. --notes-file - reads Markdown from standard input. Edit changes only supplied fields: --title='' and --notes='' clear them; --publish and --no-prerelease clear the corresponding flags.

Create uploads all --asset files, then prints the release web URL and id. Each asset's name is the file basename; an optional #LABEL sets its display label (quote it). Upload accepts multiple file arguments, including shell-expanded globs. For create, repeat --asset for each file. Content type is detected from the extension, or sniffed from the first bytes; upload's --content-type overrides it. A duplicate name fails with a hint to use --clobber. A failed upload after create leaves the release in place and reports its id.

List defaults to 30 entries and follows server pagination up to --limit. View shows fields, notes and an asset table; --notes prints Markdown alone. Create, list and view support stable JSON (fields are listed in their help). Delete removes the release and assets, not its Git tag; it asks for confirmation only on a terminal unless --yes is given.

Download defaults to all assets, into --dir (default .). Repeat --name or quote and repeat --pattern to select a union of names and globs. Files are never overwritten. One interrupted stream is resumed automatically from the bytes already received; size and SHA-256 digest are verified. Failed or mismatching downloads are removed. Resume is within the command, not across invocations.

Output

  • --json prints stable field names (listed in each --help) on repo list|show|create|edit, issue create|list|show|comment|close|resolve|reopen, token create|list, run list|view|cancel|rerun, runner list, mirror key|config|status and version.
  • watch --json prints one object per line. merge_request_mergeability events carry mergeability (state, behind, conflict_paths…) and print as repo!n mergeability: behind by 2.
  • A merge needs passing checks on the head (no failed, queued or running checks); a head with no checks can merge. mr merge --ignore-checks bypasses this, needs mr:force-merge, and cannot be combined with --auto or --cancel-auto. The cli preset includes mr:force-merge; agent does not. Adding --scope mr:merge lets an agent merge only with passing checks.
  • mr merge --mode squash|merge creates a commit signed by the server's own key (generated on first start); the output names its fingerprint, ermite signing-key show prints the key. Every mode is allowed by default; repo edit --merge-modes fast-forward,squash disables merge.
  • mr merge --auto makes the server merge once CI passed on the head (repo edit --allow-auto-merge first); --cancel-auto cancels it; both are exclusive with each other and --auto with --delete-branch. watch --json adds merge_request_auto_merge_enabled, merge_request_auto_merge_cancelled (with reason), and auto (true) on merge_request_merged after an auto-merge. See Merge requests.
  • Errors are one line on stderr (ermite: …) with exit status 1.
  • Shell completion completes repository names from the server.

ermite mr create and ermite mr close print a confirmation followed by the full merge request web URL on its own line. With --json, merge request objects (create, show, list, close and merge) include url alongside the other fields.

source
1# CLI
2
3The `ermite` binary also drives a running server over its API. Run `ermite <command> --help` for the details of each command.
4
5## Connect to a server
6
7| Setting | Environment | Config file key |
8|---|---|---|
9| server address | `ERMITE_URL` | `url` |
10| token (optional for public reads) | `ERMITE_TOKEN` | `token.cmd`, a command that prints it |
11
12The environment wins over the config file.
13
14```sh
15ermite config set url https://git.example.com
16ermite config set token.cmd 'pass show ermite/token'
17ermite config show [--json]   # path and values
18ermite config unset <key>
19```
20
21The file holds no secret, only the command that fetches the token (`pass`, `gopass show -o`, `op read`, `secret-tool lookup`, …):
22
23```ini
24# ~/.config/ermite/config
25url       = https://git.example.com
26token.cmd = pass show ermite/token
27```
28
29Location: `$XDG_CONFIG_HOME/ermite/config`, `~/Library/Application Support/ermite/config` on macOS, `%AppData%\ermite\config` on Windows. `ERMITE_CONFIG` names another file.
30
31A token sent over plain `http://` to a non-loopback host prints a warning.
32
33### How `token.cmd` runs
34
35- Through `sh -c` (`cmd /C` on Windows), at most once per run, only when a command needs the token.
36- It gets your terminal when stdin is one, so pinentry or biometric prompts work.
37- It must print the token alone on one line, under 4 KiB, within 60 seconds. On timeout or interrupt it is killed.
38- A failure is reported in one line, without the command's output.
39
40It does not run:
41
42- when `ERMITE_TOKEN` is set;
43- for `ermite version`, `ermite config` or shell completion;
44- when `ERMITE_URL` points to another server than the file's `url` (the call is anonymous; set `ERMITE_TOKEN`);
45- when the file or its directory is writable by other users, or owned by another user (not checked on Windows).
46
47## Commands
48
49```sh
50ermite repo list | show <name> | create <name> [--description …] [--visibility public]
51ermite repo edit <name> [--description …] [--visibility …] [--default-branch …] [--merge-modes …] [--allow-auto-merge] [--issues off|owner|public]
52ermite repo delete <name> [--yes]
53
54ermite token create <label> [--preset cli|agent|ci|runner] [--scope …] [--repo …] [--branch-prefix …] [--expires 30d]
55ermite token list | revoke <id>
56
57ermite mr create <repo> --source <branch> --title … | list <repo> | show <repo> <n> [--diff]   # show prints the mergeability: up to date, behind, conflict
58ermite mr comment <repo> <n> -m … [--path … --line N|A-B --side old|new] [--reply <id>] [--approve|--request-changes]
59ermite mr resolve <repo> <n> <comment> | edit-comment <repo> <n> <comment> -m … | delete-comment <repo> <n> <comment>
60ermite mr ready <repo> <n>                 # removes WIP:/[WIP], needs mr:write
61ermite mr merge <repo> <n> --head <id> [--mode fast-forward|squash|merge] [--delete-branch] [--ignore-checks] | merge <repo> <n> --head <id> --auto [--mode …] | merge <repo> <n> --cancel-auto | close <repo> <n>
62
63ermite issue create <repo> --title … [--body … | --body-file …] | list <repo> [--state open|closed|resolved|all]
64ermite issue show <repo> <n> | comment <repo> <n> -m … | close <repo> <n> | resolve <repo> <n> | reopen <repo> <n>
65# issue show prints `resolved by !N` when a merge resolved it, linked merge requests, and timestamped history interleaved with comments; --json adds closed_by_merge_request, references and events
66# mr show lists linked issues (number, state, resolves marker) and their history; --json adds issues and issue_events
67
68ermite run list <repo> [--workflow …] [--branch …] [--status …]
69ermite run view <repo> <id> [--attempt n] [--log [--job …]] [--summary]
70ermite run watch <repo> <id> [--log] | cancel <repo> <id> | rerun <repo> <id> [--failed]
71ermite run artifacts <repo> <id> | download <repo> <id> [--name N]… [--dir D]
72ermite workflow run <file> --repo <repo> [--ref …] [-f name=value …]
73ermite workflow list <repo> [--json]
74ermite workflow disable <repo> <file>    # no event starts a run of it; the file need not exist yet
75ermite workflow enable <repo> <file>
76ermite runner list | remove <id>
77ermite secret set|list|delete …         # CI secrets (needs ERMITE_SECRETS_KEY)
78ermite variable set|get|list|delete …
79ermite environment create|list|delete … --repo <repo>
80
81ermite mirror key show | rotate          # SSH key to add to the remote (rotate: owner only)
82ermite mirror config [--enabled] [--url …{repo}…] [--cron …] [--all-branches] | config show   # global policy, owner only
83ermite mirror add <repo> <url> [--cron …] [--all-branches] | remove <repo> | exclude <repo> | include <repo>
84ermite mirror status [repo] | sync <repo>|--all [--force]   # sync --all: one row per repository, exit 1 if any failed
85
86ermite web login                         # one-time sign-in link (60 s)
87ermite web logout --all                  # sign every browser out
88ermite web passkey list | remove <id>
89ermite signing-key show                  # public key of squash and merge commits (server-signed)
90ermite oidc rotate-key
91ermite watch [repo] [--json]             # follow live events
92ermite version                           # client and server versions
93ermite completion bash|zsh|fish
94```
95
96Issues need a server with the `issues` feature and `ermite repo edit <repo> --issues owner` (or `--issues public`, which also opens a moderated form to visitors of a public repository); they are written with the `issue:write` scope. An issue is `open`, `closed` (not resolved), or `resolved`. `issue resolve <repo> <n>` marks an open issue fixed (`issues.resolve` feature); merging a request with `Fixes #N` resolves it too. `issue reopen` accepts closed and resolved issues. History records references, closing, reopening and resolution with the actor and timestamp; removed references keep their history. See [Issues](issues.md).
97
98Mirrors push repositories to a remote over SSH, never forcing. See [Push mirror](mirror.md).
99
100## Releases
101
102Releases need a server advertising the `releases` feature. Published releases follow
103repository visibility; drafts are visible only to release writers. Writes need
104`release:write` (included in the `cli` token preset); branch-limited tokens cannot
105write releases. On an older server the preset drops this scope with a note, while
106an explicit `--scope release:write` fails before creating a token.
107
108```sh
109ermite release create <repo> <tag> [--title T] [--notes TEXT | --notes-file F] [--target REF] [--draft] [--prerelease] [--latest] [--asset FILE[#LABEL]]… [--json]
110ermite release list <repo> [--limit N] [--json]
111ermite release view <repo> <tag|id|latest> [--json | --notes]
112ermite release edit <repo> <tag|id> [--title T] [--notes TEXT | --notes-file F] [--tag NEW] [--target REF] [--draft | --publish] [--prerelease | --no-prerelease] [--latest]
113ermite release delete <repo> <tag|id> [--yes]
114ermite release upload <repo> <tag|id> FILE[#LABEL]… [--clobber] [--content-type T]
115ermite release download <repo> <tag|id|latest> [--pattern GLOB]… [--name N]… [--dir D]
116```
117
118All-digit selectors are release ids; other selectors are tags. `latest` selects
119the latest release for view/download. `--latest` pins a release as latest.
120Non-draft releases require an existing tag, or `--target` to create one; an
121existing tag is never moved. `--notes-file -` reads Markdown from standard input.
122Edit changes only supplied fields: `--title=''` and `--notes=''` clear them;
123`--publish` and `--no-prerelease` clear the corresponding flags.
124
125Create uploads all `--asset` files, then prints the release web URL and id.
126Each asset's name is the file basename; an optional `#LABEL` sets its display
127label (quote it). Upload accepts multiple file arguments, including shell-expanded
128globs. For create, repeat `--asset` for each file. Content type is detected from
129the extension, or sniffed from the first bytes; upload's `--content-type` overrides
130it. A duplicate name fails with a hint to use `--clobber`. A failed upload after
131create leaves the release in place and reports its id.
132
133List defaults to 30 entries and follows server pagination up to `--limit`.
134View shows fields, notes and an asset table; `--notes` prints Markdown alone.
135Create, list and view support stable JSON (fields are listed in their help).
136Delete removes the release and assets, not its Git tag; it asks for confirmation
137only on a terminal unless `--yes` is given.
138
139Download defaults to all assets, into `--dir` (default `.`). Repeat `--name` or
140quote and repeat `--pattern` to select a union of names and globs. Files are never
141overwritten. One interrupted stream is resumed automatically from the bytes
142already received; size and SHA-256 digest are verified. Failed or mismatching
143downloads are removed. Resume is within the command, not across invocations.
144
145## Output
146
147- `--json` prints stable field names (listed in each `--help`) on `repo list|show|create|edit`, `issue create|list|show|comment|close|resolve|reopen`, `token create|list`, `run list|view|cancel|rerun`, `runner list`, `mirror key|config|status` and `version`.
148- `watch --json` prints one object per line. `merge_request_mergeability` events carry `mergeability` (`state`, `behind`, `conflict_paths`…) and print as `repo!n mergeability: behind by 2`.
149- A merge needs passing checks on the head (no failed, queued or running checks); a head with no checks can merge. `mr merge --ignore-checks` bypasses this, needs `mr:force-merge`, and cannot be combined with `--auto` or `--cancel-auto`. The `cli` preset includes `mr:force-merge`; `agent` does not. Adding `--scope mr:merge` lets an agent merge only with passing checks.
150- `mr merge --mode squash|merge` creates a commit signed by the server's own key (generated on first start); the output names its fingerprint, `ermite signing-key show` prints the key. Every mode is allowed by default; `repo edit --merge-modes fast-forward,squash` disables `merge`.
151- `mr merge --auto` makes the server merge once CI passed on the head (`repo edit --allow-auto-merge` first); `--cancel-auto` cancels it; both are exclusive with each other and `--auto` with `--delete-branch`. `watch --json` adds `merge_request_auto_merge_enabled`, `merge_request_auto_merge_cancelled` (with `reason`), and `auto` (true) on `merge_request_merged` after an auto-merge. See [Merge requests](merge-requests.md#auto-merge).
152- Errors are one line on stderr (`ermite: …`) with exit status 1.
153- Shell completion completes repository names from the server.
154
155`ermite mr create` and `ermite mr close` print a confirmation followed by the full
156merge request web URL on its own line. With `--json`, merge request objects
157(create, show, list, close and merge) include `url` alongside the other fields.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 4

Tags 45

↑↓ moveenter openesc close