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
- 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.
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> --squash --delete-branch
Give the agent the skills/ermite skill so it knows the CLI. Rules of agent tokens: docs/tokens.md.
Documentation
- Configuration: environment variables
- CLI: config file, commands, JSON output
- Git over HTTP: URLs and authentication
- Tokens: scopes, presets, branch-limited tokens
- Merge requests
- Commit signatures: SSH and OpenPGP badges, trusted keys
- Web sign-in: passkeys and one-time links
- CI: runners, trust, concurrency, reusable workflows
- Development: build, tests, architecture
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- Git over HTTPS, web interface with live updates
22
23Status: early development.
24
25## GitHub Actions
26
27Push a repository with a `.github/workflows` folder and its workflows run, the same YAML you use on GitHub:
28
29- Events: `push`, `pull_request`, `pull_request_target`, `workflow_dispatch`, `schedule`, `workflow_run`, `create`, `delete`
30- Matrix, `needs`, `concurrency`, reusable workflows, job outputs and summaries
31- Secrets, variables, environments and OIDC (`id-token: write`)
32- `actions/checkout`, `actions/cache`, `setup-*`, `upload-artifact` / `download-artifact` v4
33- Actions from github.com or from your own ermite repositories
34- Each job is a check on the commit and the merge request; failing checks block the merge
35
36A feature ermite does not support fails with `not supported yet: <feature>`, never silently.
37
38### Runner
39
40Jobs run on [ermite-runner](https://github.com/bnema/ermite-runner) hosts, one fresh sandbox per job:
41
42- **microVM** (Firecracker) when `/dev/kvm` is available: each job gets its own kernel, destroyed at the end
43- **container** with its own Docker daemon otherwise
44
45```sh
46ermite token create runner-1 --preset runner # then register the runner with this token
47ermite runner list
48```
49
50CI turns on as soon as a runner is registered. Details: [docs/ci.md](docs/ci.md).
51
52## Run
53
54```sh
55docker build -t ermite .
56token=$(head -c 32 /dev/urandom | base64) # keep it: it is the root credential
57docker run -d -p 127.0.0.1:7341:7341 -v ermite-data:/data \
58 -e ERMITE_PUBLIC_URL=http://localhost:7341 -e ERMITE_ADMIN_TOKEN="$token" ermite
59```
60
61Without 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.
62
63All settings: [docs/configuration.md](docs/configuration.md).
64
65## Use
66
67Point the CLI at the server:
68
69```sh
70ermite config set url https://git.example.com
71ermite config set token.cmd 'pass show ermite/token' # any command that prints the token
72```
73
74Then:
75
76```sh
77ermite repo create myrepo
78git push https://x:<token>@git.example.com/myrepo.git main # prefer a credential helper
79ermite mr create myrepo --source feature --title "Add feature"
80ermite web login # one-time link to sign in to the web interface
81```
82
83Pushing to a new name also creates a private repository.
84
85## Agent workflow
86
87You 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.
88
89**1. You give the agent a token** limited to `agent/claude/*`:
90
91```sh
92ermite token create claude --preset agent --scope repo:read --repo myrepo --branch-prefix agent/claude/ --expires 30d
93```
94
95**2. The agent pushes and opens a merge request:**
96
97```sh
98export ERMITE_URL=https://git.example.com ERMITE_TOKEN=<agent token>
99git push origin agent/claude/fix-login
100ermite mr create myrepo --source agent/claude/fix-login --title "Fix login redirect"
101ermite run watch myrepo <run id> # follow its CI
102```
103
104**3. You review:**
105
106```sh
107ermite mr show myrepo 1 --diff
108ermite mr comment myrepo 1 -m "Handle the empty case" --path auth.go --line 42 --side new
109```
110
111**4. The agent reads your comments and pushes again:**
112
113```sh
114ermite watch myrepo --json # live events: pushes, merge requests, comments
115ermite mr show myrepo 1 --since-last-read --mark-read
116```
117
118**5. You merge** (or click Merge in the web interface):
119
120```sh
121ermite mr merge myrepo 1 --head <head id> --squash --delete-branch
122```
123
124Give 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).
125
126## Documentation
127
128- [Configuration](docs/configuration.md): environment variables
129- [CLI](docs/cli.md): config file, commands, JSON output
130- [Git over HTTP](docs/git-http.md): URLs and authentication
131- [Tokens](docs/tokens.md): scopes, presets, branch-limited tokens
132- [Merge requests](docs/merge-requests.md)
133- [Commit signatures](docs/commit-signatures.md): SSH and OpenPGP badges, trusted keys
134- [Web sign-in](docs/web-sign-in.md): passkeys and one-time links
135- [CI](docs/ci.md): runners, trust, concurrency, reusable workflows
136 - [CI events](docs/ci-events.md)
137 - [OIDC](docs/ci-oidc.md)
138 - [Artifacts](docs/ci-artifacts.md)
139- [Development](docs/development.md): build, tests, architecture
140
141## License
142
143AGPL-3.0-or-later. See [LICENSE](LICENSE).