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.