Forgejo LLM agent
  • Go 78.7%
  • Nix 21.3%
Find a file
sid 54a1f9990f
All checks were successful
Flake check / flake-check (push) Successful in 14s
initial commit
2026-09-14 13:50:21 +02:00
.forgejo/workflows initial commit 2026-09-14 13:50:21 +02:00
controller initial commit 2026-09-14 13:50:21 +02:00
module initial commit 2026-09-14 13:50:21 +02:00
pkgs initial commit 2026-09-14 13:50:21 +02:00
tests initial commit 2026-09-14 13:50:21 +02:00
.gitignore initial commit 2026-09-14 13:50:21 +02:00
flake.lock initial commit 2026-09-14 13:50:21 +02:00
flake.nix initial commit 2026-09-14 13:50:21 +02:00
README.md initial commit 2026-09-14 13:50:21 +02:00

Forgejo agent

A NixOS module that turns a Forgejo bot user into an opencode-driven agent. Issues and pull requests drive it through a label state machine. Each job runs in its own throwaway systemd sandbox on the host.

The controller (forgejo-agent-controller) runs as a systemd service. A webhook posts issues and issue_comment events to http(s)://<agent-host>/hook/<agent-name>, which the controller verifies and classifies. It then moves labels, branches, and opens PRs using the bot's token. A successful implement job opens a PR for a human to merge (the bot never merges).

Configure

Import the flake module and apply its overlay:

{ inputs, ... }: {
  imports = [ inputs.forgejoAgent.nixosModules.forgejoAgent ];
  nixpkgs.overlays = [ inputs.forgejoAgent.overlays.default ];
}

Then enable it in your configuration:

{ pkgs, ... }: {
  services.forgejoAgent = {
    enable = true;

    llm = {
      model = "openai/gpt-6-astra";
      apiKeyFile = "/run/secrets/forgejo-agent/llm-key";
    };

    harness.tools = [ pkgs.jq pkgs.ripgrep ];

    agents.main = {
      forgejoUrl = "https://git.example.com";
      botUsername = "forgejo-agent";
      botTokenFile = "/run/secrets/forgejo-agent/bot-token";
      webhookSecretFile = "/run/secrets/forgejo-agent/webhook-secret";
    };
  };
}

Required options: llm.model, llm.apiKeyFile, at least one agents.<name> with forgejoUrl, botUsername, botTokenFile, webhookSecretFile.

One-time setup

  1. Create the bot user and a personal access token that can read/write issues, push branches, open PRs, and manage labels.
  2. Invite the bot as a collaborator with write permission on each repo.
  3. Register a webhook per repo pointing at https://<agent-host>/hook/<name>. Content type JSON, enable issues and issue_comment, and set the secret to the value of webhookSecretFile. Test with "Test Delivery".

The controller binds 127.0.0.1:8150 by default. For an external instance, front it with a reverse proxy that forwards /hook/ and /healthz.

If Forgejo and the agent share a machine, allow loopback webhook delivery:

services.forgejo.settings.webhook.ALLOWED_HOST_LIST = "loopback";

Usage

Want the agent to Do this
Implement an issue Apply bot:run to an open issue
Review a PR Apply bot:review to a PR, or @<bot>-mention it
Triage an issue @<bot>-mention it in an issue comment

Labels the controller manages:

  • bot:run: trigger label on an issue that starts an implement job.
  • bot:review: trigger label on a PR that starts a review job.
  • bot:running: set while a job is running. The bot keeps it on until it finishes.
  • bot:needs-review: set when an implement job opens a PR for a human to review.
  • bot:done: set after a job completes successfully.
  • bot:failed: set when a job fails or times out.

labelsAutoCreate = true (default) creates missing labels. Where a collaborator can't create labels, pre-create them once with an admin.