If you've ever managed a Gitea or Forgejo instance for more than a handful of people, you know the drill. New hire? Click through the web UI to create a user, add them to an org, assign team permissions, grant repo access. Someone leaves? Reverse the whole thing. Need to replicate the setup on a second instance? Good luck doing it by hand without missing something.

It's the kind of work that feels manageable at five users and unbearable at fifty. And if you're running multiple instances—staging, production, a self-hosted lab—you're doing it all over again for each one.

TL;DR: Infuser-Go is a declarative IaC tool for Gitea and Forgejo. You define your users, organizations, teams, and repositories in YAML files. It reconciles the desired state against the server—dry-run by default, apply when ready. Think Terraform, but for your self-hosted Git server. It's open source and looking for early adopters.

The Problem: Click-Ops Doesn't Scale

Self-hosted Git servers like Gitea and Forgejo are excellent. They're lightweight, fast, and give you full control over your source code infrastructure. But they share a blind spot with most self-hosted tools: administration is manual.

There's no native way to say "here's my desired state—make it so." Every user, every org, every team membership is a series of web forms or raw API calls. That means:

  • No audit trail beyond server logs—you can't git-blame who granted access to what
  • No environment parity—your staging and production instances drift apart silently
  • No disaster recovery plan—if you lose the instance, you lose the organizational structure with it
  • No automation path—onboarding scripts become fragile chains of curl commands

If you're coming from the Kubernetes or Terraform world, this feels like stepping back in time. Infrastructure-as-code solved these problems for servers, networks, and cloud resources years ago. Self-hosted Git servers never got the same treatment.

What Infuser-Go Does

Infuser-Go is a reconciliation engine. You describe what your Gitea or Forgejo instance should look like in YAML files, and the tool figures out the difference between that desired state and reality. Then it either shows you the diff (dry-run, the default) or applies the changes.

The configuration lives in a directory structure that mirrors your server's organizational hierarchy:

infuser-config/production/
├── users/
│   ├── alice/
│   │   ├── user.yaml
│   │   └── repositories/
│   │       └── my-project.yaml
│   └── bob/
│       └── user.yaml
└── organizations/
    └── engineering/
        ├── org.yaml
        ├── teams/
        │   ├── backend.yaml
        │   └── frontend.yaml
        └── repositories/
            └── api-service.yaml

Each YAML file declares the desired state for that resource. The tool handles creation, updates, and reconciliation. The workflow is intentionally simple:

  1. Export your current server state into YAML files (bootstrap from reality)
  2. Edit the YAML to declare your desired changes
  3. Preview the diff with a dry-run (the default—nothing happens unless you say so)
  4. Apply with --apply when you're satisfied

Safety Is Not Optional

The fastest way to lose trust in an infrastructure tool is for it to delete something it shouldn't. Infuser-Go is designed with that lesson baked in:

  • Dry-run by default. Every run is a preview unless you explicitly pass --apply. You always see what would happen before it does.
  • Write protection. Write operations require an explicit allow_writes: true in your server configuration. Read-only mode is the default.
  • Interactive confirmation. Before applying changes, you get a confirmation prompt. For CI/CD pipelines, you can bypass it with --auto-approve—but that's a conscious opt-in.
  • Temporary passwords. New users get random passwords with a forced change on first login. No hardcoded credentials in your config files.

These aren't features. They're the minimum bar for a tool that touches your source code infrastructure.

Multi-Server, One Config

If you're running more than one Gitea or Forgejo instance, Infuser-Go lets you manage all of them from a single servers.yaml:

servers:
  production:
    url: https://gitea.company.com
    read_token_env: PROD_READ_TOKEN
    write_token_env: PROD_WRITE_TOKEN
    allow_writes: true

  staging:
    url: https://gitea-staging.company.com
    read_token_env: STAGING_READ_TOKEN
    allow_writes: false

Target a specific server with --server production, or run reconciliation across all of them. Tokens are referenced via environment variables—no secrets in your repo.

The GitOps Angle

Because your entire server configuration lives in YAML files, you get all the GitOps benefits for free:

  • Version control. Every change to your infrastructure is a commit. You can diff, blame, and revert.
  • Code review. New team member needs access? That's a pull request, not a Slack message to an admin.
  • CI/CD integration. Run infuser --apply --auto-approve --server production in your pipeline. Infrastructure changes ship with the same rigor as code changes.
  • Environment replication. Spin up a new instance and point Infuser-Go at it. Your entire org structure materializes in seconds.

This is how infrastructure should work. Declare it, version it, automate it.

Getting Started

Infuser-Go is written in Go and builds to a single binary:

git clone https://github.com/augustose/infuser-go.git
cd infuser-go
go build -o infuser .

From there, the interactive TUI guides you through connecting to your first server. Or, if you prefer the command line:

# Export current state as a starting point
go run ./cmd/export/

# Preview what reconciliation would do
go run ./cmd/reconcile/

# Apply changes
go run ./cmd/reconcile/ --apply

# Generate a report of repos, owners, and access
go run ./cmd/report/

What's Next—And How You Can Help

Infuser-Go is in active development. The core reconciliation loop works. Export, preview, and apply are functional. Multi-server support is in place. But there's more to build, and this is where you come in.

If you're running Gitea or Forgejo and you've felt the pain of manual administration, I'd genuinely like to hear from you. Whether you want to:

  • Test it against your own instance and report what breaks
  • Contribute features, fixes, or documentation
  • Talk about your use case and what you'd need from a tool like this

The project is MIT-licensed and open to all of it. The best way to reach me is through GitHub Issues on the repo, or directly at augustose@gmail.com.

You don't need permission to start. Clone it, point it at a test instance, run a dry-run, and see what it finds. The worst that can happen is you learn something about your own server's state that you didn't know.


Infuser-Go is available at github.com/augustose/infuser-go. MIT License. Inspired by Goliac.