Previously, GitRoot served as a Source Code Management (SCM) system, allowing you to create Git repositories and manage access permissions. However, GitRoot was never intended to be just an SCM. With this v0.3.0 release, it evolves into a full-fledged forge.
To activate this new capability on your instance, follow the administrator section. To start using it as a user, see the user section.
The introduction of executors brings a crucial new feature: the report and reporter plugin API. This API allows any plugin to provide informational feedback to the user. Important: avoid reporting low-level technical details here (use the log and logError APIs for that). The initial implementation uses this feature to display command statistics (CPU, memory, etc.) from the new hop plugin in a clean table via the grafter plugin.
With the new hop plugin, GitRoot now supports 3 languages (Go, TypeScript, Rust) across 4 compilers (Go, TinyGo, Rust, AssemblyScript). Setting up a development environment for this polyglot stack is complex, and keeping it updated is even harder, unless you have the right tools. For this iteration, I have selected mise as the default tool for managing the GitRoot dev environment.
Beyond technical features, a new focus has been placed on communication. You can now follow daily progress on our new fediverse instance (@forge@gitroot.dev), engage in direct chat on matrix (#gitroot:matrix.org), and read a new blog post detailing concrete ways to contribute today.
Finally, I discuss Apex and many other tiny but useful things.
When you update GitRoot to 0.3.0 a new configuration block will appear in the .gitroot/forgeConfig.yml file of your root repository:
1execconf:
2 baremetal:
3 enabled: false
4 bwrap:
5 enabled: false
6 user: nobody
7 uid: 65534
8 gid: 65534
9 robind: []
10 bind: []
11 container:
12 enabled: false
13 bin: podman
14 ssh:
15 enabled: false
16 hosts:
17 - user: myUSer
18 address: 127.0.0.1
19 port: 22
20 publickey: ssh-ed25519 AAAAC3NzaC1...
You can enable multiple executors, but GitRoot will only use the first one enabled, checking them in this order:
bareMetal,bwrap,containerand thenssh. If you activate an executor, remember to also add thehopplugin, as it is the only known plugin designed to utilize them.
The bareMetal executor runs commands directly on the host machine. It requires no external dependencies and should work on any hardware. Be extremely cautious: users of your GitRoot instance will gain the ability to execute arbitrary code on the host.
The bwrap executor introduces a lightweight container (sandbox) between executed commands and the host, similar to the technology used by flatpack. To use it, you must install the bubblewrap application.
By default, GitRoot configures bwrap to use the nobody user for restriction, though this can be changed. You can also define bindings between your host and the commands running inside the container. For example, robind: ["/var/log/caddy/access.log"] would allow a job to execute cat /var/log/caddy/access.log.
The container executor enables the execution of commands within podman or docker containers, allowing your users to run any OCI image. The only requirement for the administrator is to install either podman or docker. Remember to change the bin property to docker if that is your chosen runtime.
GitRoot includes a useful feature for containers: if the user provides a path to a Containerfile or Dockerfile, GitRoot will automatically build the image before running commands inside it.
The ssh executor allows commands to be executed on a remote host via a standard SSH connection. You simply provide the standard SSH connection details. This executor should be considered the most alpha of all options (and yes, all others are also considered alpha).
hop pluginTo execute a build (or command execution), users must activate the hop plugin and configure its execution rules:
1- url: /home/rmaneschi/projects/gitroot/app/testsuite/../plugins/hop/hop-0.0.1.wasm
2 name: hop
3 version: 0.0.1
4 active: true
5 run:
6 - path: "*"
7 branch:
8 - "*"
9 when:
10 - add
11 - mod
12 write:
13 git: []
14 web: []
15 exec:
16 - command: cat
17 configuration:
18 exec:
19 build: ""
20 cmds:
21 - args:
22 - README.md
23 cmd: cat
24 env: []
Add all desired commands for the plugin to call in run.write.exec.
Then in run.configuration.exec:
env (e.g., "MY_ENV=my_val")build property (only for the container executor) to use an existing image (e.g., docker.io/bash:5.3.3) or to build one from a file (e.g., /my/path/to/Containerfile)cmdsOccasionally, plugins need to communicate important information to the user. For instance, the ladybug plugin might need to report invalid metadata. In traditional forges, a web interface serves this purpose, but GitRoot operates without a fixed UI.
Past considerations included sending emails (a solution often disliked by developers) or leveraging external communication methods like RSS via the pollen plugin (introduced in v0.2.0) or the Fediverse via a Go-to-Social instance. As always, GitRoot aims to provide options rather than dictate a single solution.
To allow reporting without forcing a communication channel, I’ve created two new plugin APIs.
Report: plugins call this API with a severity level (info, warn, or error) and an array of strings to display. GitRoot stacks all reports for every commit and plugin.
Reporter API: after reports are collected, GitRoot calls all plugins that implement the Reporter interface.
Currently, the grafter plugin is the only known reporter; it adds the collected reports to the graft output. This two new API opens up a wide range of possibilities for future versions. I have several ideas, but I encourage you to share yours!
Managing a diverse development environment that spans Go, TypeScript, and Rust can be a significant hurdle. In this iteration, I have standardized on mise as the official tool for managing the GitRoot dev environment. This choice simplifies installation and ensures all dependencies remain correctly updated for development.
This choice seems to be a good one, as we welcome a new contributor who has already integrated some common tasks using mise. Thanks to their efforts, we can now simply run mise run build to compile GitRoot or mise run test to execute all tests.
Alongside the technical work for v0.3.0, a focused effort was put into non-technical tasks to improve communication with the community.
To allow you to follow daily progress and current thoughts, I have set up a GoToSocial (Mastodon) instance. You can find the official account at @forge@gitroot.dev or directly at https://gts.gitroot.dev. This is the best place for real-time updates.
I also established a direct chat room on matrix, accessible via https://matrix.to/#/#gitroot:matrix.org. Feel free to stop by to ask questions or just say hello.
I’ve added a contact page to ensure you can easily find a way to reach me. It includes multiple options such as email, mastodon, or matrix for direct chat. Please don’t hesitate to come say “hi”!
Finally, I published a blog post titled “How to help building GitRoot 11-2025”. The purpose of this post is to present you with concrete, immediate contribution opportunities, rather than speculating on future possibilities. If you wish to get involved, this is the place to start.
The Apex plugin receives numerous bug fixes and quality of life improvements:
og (Open Graph) or fediverse metadataBreaking: previously, the apex plugin rendered markdown metadata as small blocks at the top of the page by default. With this version, it will no longer render this metadata unless the markdown page explicitly includes apexRenderMetadatas: true in its front matter.
Although this article is already quite long, I want to briefly mention several smaller yet important tasks completed in this release.
The parameters externalsshaddr (default value ssh://localhost:4545/) and externalhttpaddr (default value http://localhost:4546/) have been added to ensure the display of correct external urls to users. These addresses are notably used by the apex plugin generate proper public links. They are kept separate from the internal sshaddr and httpaddr because your GitRoot instance might be configured to listen internally (on 127.0.0.1) while being reachable externally through a reverse proxy.
I’ve added a preliminary implementation for an integrated updater. This feature will handle breaking changes gracefully. For this release, I’ve added some new parameters to forgeConf.yml, the integrated updater will handle these by setting standard values that should not affect your current user instance setup.
While integrating Rust, I discovered that the WASM (and specifically WASI Preview 1) target does not permit exporting the standard free and malloc functions, which GitRoot requires. I’ve added an option to rename these functions to gitrootAlloc and gitrootFree, resolving this compatibility issue.