v0.32.0 53e25a3

README.md RawHistoryFolder

Read-only mirror. Development happens at git.bnema.dev; issues and pull requests are closed here.


Features

  • GitHub Actions, as is: your .github/workflows run unchanged, marketplace actions included
  • Isolated runner: ermite-runner runs each job in a Firecracker microVM when KVM is available, else in a container
  • CLI-first: repositories, merge requests, reviews and CI all work from the ermite CLI, for you and for AI agents
  • Safe for agents: an agent token can only push its own branches; you review and merge
  • Releases with a GitHub-compatible API, CLI and web downloads; assets and CI artifacts on disk or S3-compatible storage
  • Git over HTTPS, web interface with live updates

Status: early development.

GitHub Actions

Push a repository with a .github/workflows folder and its workflows run, the same YAML you use on GitHub:

  • Events: push, pull_request, pull_request_target, workflow_dispatch, schedule, workflow_run, create, delete
  • Matrix, needs, concurrency, reusable workflows, job outputs and summaries
  • Secrets, variables, environments and OIDC (id-token: write)
  • actions/checkout, actions/cache, setup-*, upload-artifact / download-artifact v4
  • Actions from github.com or from your own ermite repositories
  • Each job is a check on the commit and the merge request; failing checks block the merge

A feature ermite does not support fails with not supported yet: <feature>, never silently.

Runner

Jobs run on ermite-runner hosts, one fresh sandbox per job:

  • microVM (Firecracker) when /dev/kvm is available: each job gets its own kernel, destroyed at the end
  • container with its own Docker daemon otherwise
ermite token create runner-1 --preset runner   # then register the runner with this token
ermite runner list

CI turns on as soon as a runner is registered. Details: docs/ci.md.

Run

docker build -t ermite .
token=$(head -c 32 /dev/urandom | base64)   # keep it: it is the root credential
docker run -d -p 127.0.0.1:7341:7341 -v ermite-data:/data \
  -e ERMITE_PUBLIC_URL=http://localhost:7341 -e ERMITE_ADMIN_TOKEN="$token" ermite

Without Docker, set ERMITE_DATA_DIR, ERMITE_PUBLIC_URL and ERMITE_ADMIN_TOKEN, then run ermite serve. Requires git 2.45 or newer. Put a TLS proxy in front of it.

All settings: docs/configuration.md.

Use

Point the CLI at the server:

ermite config set url https://git.example.com
ermite config set token.cmd 'pass show ermite/token'   # any command that prints the token

Then:

ermite repo create myrepo
git push https://x:<token>@git.example.com/myrepo.git main   # prefer a credential helper
ermite mr create myrepo --source feature --title "Add feature"
ermite web login   # one-time link to sign in to the web interface

Pushing to a new name also creates a private repository.

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.

Agent workflow

You and the agent use the same CLI. The difference is the token: the agent's is limited to its own branches. It can never push main, tags or settings, and its CI runs get no secrets.

1. You give the agent a token limited to agent/claude/*:

ermite token create claude --preset agent --scope repo:read --repo myrepo --branch-prefix agent/claude/ --expires 30d

2. The agent pushes and opens a merge request:

export ERMITE_URL=https://git.example.com ERMITE_TOKEN=<agent token>
git push origin agent/claude/fix-login
ermite mr create myrepo --source agent/claude/fix-login --title "Fix login redirect"
ermite run watch myrepo <run id>         # follow its CI

3. You review:

ermite mr show myrepo 1 --diff
ermite mr comment myrepo 1 -m "Handle the empty case" --path auth.go --line 42 --side new

4. The agent reads your comments and pushes again:

ermite watch myrepo --json               # live events: pushes, merge requests, comments
ermite mr show myrepo 1 --since-last-read --mark-read

5. You merge (or click Merge in the web interface):

ermite mr merge myrepo 1 --head <head id> --mode squash --delete-branch

Give the agent the skills/ermite skill so it knows the CLI. Rules of agent tokens: docs/tokens.md.

Documentation

License

AGPL-3.0-or-later. See LICENSE.

source
1<h1 align="center">ermite</h1>
2
3<p align="center">
4  <a href="LICENSE"><img src="https://img.shields.io/badge/license-AGPL--3.0-blue?style=flat-square" alt="License: AGPL-3.0"></a>
5  <a href="https://github.com/bnema/ermite/commits/main"><img src="https://badgen.net/github/last-commit/bnema/ermite/main?icon=github" alt="Last commit"></a>
6  <a href="https://github.com/bnema/ermite/stargazers"><img src="https://badgen.net/github/stars/bnema/ermite?icon=github" alt="GitHub stars"></a>
7</p>
8
9<p align="center">A single-user Git forge in one Go binary.</p>
10
11> Read-only mirror. Development happens at git.bnema.dev; issues and pull requests are closed here.
12
13---
14
15## Features
16
17- **GitHub Actions, as is**: your `.github/workflows` run unchanged, marketplace actions included
18- **Isolated runner**: [ermite-runner](https://github.com/bnema/ermite-runner) runs each job in a Firecracker microVM when KVM is available, else in a container
19- **CLI-first**: repositories, merge requests, reviews and CI all work from the `ermite` CLI, for you and for AI agents
20- **Safe for agents**: an agent token can only push its own branches; you review and merge
21- **[Releases](docs/releases.md)** with a GitHub-compatible API, CLI and web downloads; assets and CI artifacts on [disk or S3-compatible storage](docs/storage.md)
22- Git over HTTPS, web interface with live updates
23
24Status: early development.
25
26## GitHub Actions
27
28Push a repository with a `.github/workflows` folder and its workflows run, the same YAML you use on GitHub:
29
30- Events: `push`, `pull_request`, `pull_request_target`, `workflow_dispatch`, `schedule`, `workflow_run`, `create`, `delete`
31- Matrix, `needs`, `concurrency`, reusable workflows, job outputs and summaries
32- Secrets, variables, environments and OIDC (`id-token: write`)
33- `actions/checkout`, `actions/cache`, `setup-*`, `upload-artifact` / `download-artifact` v4
34- Actions from github.com or from your own ermite repositories
35- Each job is a check on the commit and the merge request; failing checks block the merge
36
37A feature ermite does not support fails with `not supported yet: <feature>`, never silently.
38
39### Runner
40
41Jobs run on [ermite-runner](https://github.com/bnema/ermite-runner) hosts, one fresh sandbox per job:
42
43- **microVM** (Firecracker) when `/dev/kvm` is available: each job gets its own kernel, destroyed at the end
44- **container** with its own Docker daemon otherwise
45
46```sh
47ermite token create runner-1 --preset runner   # then register the runner with this token
48ermite runner list
49```
50
51CI turns on as soon as a runner is registered. Details: [docs/ci.md](docs/ci.md).
52
53## Run
54
55```sh
56docker build -t ermite .
57token=$(head -c 32 /dev/urandom | base64)   # keep it: it is the root credential
58docker run -d -p 127.0.0.1:7341:7341 -v ermite-data:/data \
59  -e ERMITE_PUBLIC_URL=http://localhost:7341 -e ERMITE_ADMIN_TOKEN="$token" ermite
60```
61
62Without Docker, set `ERMITE_DATA_DIR`, `ERMITE_PUBLIC_URL` and `ERMITE_ADMIN_TOKEN`, then run `ermite serve`. Requires git 2.45 or newer. Put a TLS proxy in front of it.
63
64All settings: [docs/configuration.md](docs/configuration.md).
65
66## Use
67
68Point the CLI at the server:
69
70```sh
71ermite config set url https://git.example.com
72ermite config set token.cmd 'pass show ermite/token'   # any command that prints the token
73```
74
75Then:
76
77```sh
78ermite repo create myrepo
79git push https://x:<token>@git.example.com/myrepo.git main   # prefer a credential helper
80ermite mr create myrepo --source feature --title "Add feature"
81ermite web login   # one-time link to sign in to the web interface
82```
83
84Pushing to a new name also creates a private repository.
85
86`ermite mr create` and `ermite mr close` print a confirmation followed by the full
87merge request web URL on its own line. With `--json`, merge request objects
88(create, show, list, close and merge) include `url` alongside the other fields.
89
90## Agent workflow
91
92You and the agent use the same CLI. The difference is the token: the agent's is limited to its own branches. It can never push `main`, tags or settings, and its CI runs get no secrets.
93
94**1. You give the agent a token** limited to `agent/claude/*`:
95
96```sh
97ermite token create claude --preset agent --scope repo:read --repo myrepo --branch-prefix agent/claude/ --expires 30d
98```
99
100**2. The agent pushes and opens a merge request:**
101
102```sh
103export ERMITE_URL=https://git.example.com ERMITE_TOKEN=<agent token>
104git push origin agent/claude/fix-login
105ermite mr create myrepo --source agent/claude/fix-login --title "Fix login redirect"
106ermite run watch myrepo <run id>         # follow its CI
107```
108
109**3. You review:**
110
111```sh
112ermite mr show myrepo 1 --diff
113ermite mr comment myrepo 1 -m "Handle the empty case" --path auth.go --line 42 --side new
114```
115
116**4. The agent reads your comments and pushes again:**
117
118```sh
119ermite watch myrepo --json               # live events: pushes, merge requests, comments
120ermite mr show myrepo 1 --since-last-read --mark-read
121```
122
123**5. You merge** (or click Merge in the web interface):
124
125```sh
126ermite mr merge myrepo 1 --head <head id> --mode squash --delete-branch
127```
128
129Give the agent the [`skills/ermite`](skills/ermite/SKILL.md) skill so it knows the CLI. Rules of agent tokens: [docs/tokens.md](docs/tokens.md).
130
131## Documentation
132
133- [Configuration](docs/configuration.md): environment variables
134- [CLI](docs/cli.md): config file, commands, JSON output
135- [Git over HTTP](docs/git-http.md): URLs and authentication
136- [Push mirror](docs/mirror.md): push repositories to a remote over SSH
137- [Tokens](docs/tokens.md): scopes, presets, branch-limited tokens
138- [Merge requests](docs/merge-requests.md)
139- [Issues](docs/issues.md)
140- [Commit signatures](docs/commit-signatures.md): SSH and OpenPGP badges, trusted keys
141- [Web sign-in](docs/web-sign-in.md): passkeys and one-time links
142- [CI](docs/ci.md): runners, trust, concurrency, reusable workflows
143  - [CI events](docs/ci-events.md)
144  - [OIDC](docs/ci-oidc.md)
145  - [Artifacts](docs/ci-artifacts.md)
146- [Development](docs/development.md): build, tests, architecture
147
148## License
149
150AGPL-3.0-or-later. See [LICENSE](LICENSE).

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 2

Tags 41

↑↓ moveenter openesc close