Why Leave GitHub?

GitHub is the default for good reasons: it's free, universally supported, and every tool in the ecosystem talks to it natively. But when your AI agents run on a private LAN โ€” no internet access by design โ€” GitHub becomes a liability. Every git push, every git clone, every webhook is a network call that either fails silently or requires punching a hole in your isolation boundary.

Beyond the connectivity issue, there's a simpler principle at work: for a local AI agent stack, your git server is infrastructure, not a product. You don't need project management features, CI/CD pipelines, or a social graph. You need a place for agents to push and pull code reliably, with zero maintenance overhead. The complexity that makes GitHub great for teams of humans becomes friction when the primary consumers are automated agents.

This post breaks down every viable option, with specific attention to how well each one serves AI agent workflows on an isolated network.

What Does an AI Agent Actually Need from Git?

Before evaluating options, it helps to be precise about the requirements. An AI agent doing code work needs:

What agents do not need: issue trackers, pull request UI, CI/CD runners, user management for dozens of accounts, or web-based code review. Optimizing for human features in a primarily agent-driven system adds complexity with no return.

Option 1: Bare Git over SSH

The absolute floor of git servers: a unix user account, an SSH daemon, and bare git repositories in a directory. Nothing else. Any machine running sshd and git already qualifies.

How It Works

Create a git user, add authorized SSH public keys (for each agent + human admin), and initialize bare repos:

# On the server
sudo adduser git
sudo su - git
mkdir repos && cd repos
git init --bare myproject.git

Clients push/pull with: git clone git@server:repos/myproject.git

Pros

Cons

Verdict

Right choice if you have a small, fixed set of repos that change infrequently, one or two human admins, and zero tolerance for any additional process. Wrong choice if agents need to create new repos dynamically or if you want any kind of repo discovery.

Option 2: Soft Serve

Soft Serve by Charmbracelet is a single-binary, SSH-first git server built for terminal-native workflows. It's the most elegant minimal option โ€” considerably more capable than bare git over SSH, with nearly as little operational overhead.

Key Features

โœ… The Killer Feature for AI Agents Soft Serve creates repositories automatically when an agent pushes to a new path. No human needs to pre-create the repo. An agent doing git push ssh://server/new-experiment-7 for the first time just works. This alone makes it significantly better than bare git for autonomous agent use.

Resource Usage

~5โ€“15MB RAM at idle. Negligible CPU. Runs fine on a Raspberry Pi. The SQLite database stays under a few MB for hundreds of repos.

Cons

Option 3: Forgejo

Forgejo is a community-governed fork of Gitea โ€” the lightweight GitHub clone written in Go. If Soft Serve is a sharp knife, Forgejo is a full kitchen. It does everything: web UI, issues, pull requests, webhooks, Gitea Actions (CI/CD), user management, organization support, package registry, and a comprehensive REST API that GitHub-compatible tools can talk to natively.

Why Forgejo over Gitea

Gitea is backed by Gitea Ltd., which has moved some features toward a cloud-hosted paid product. Forgejo is a non-profit fork governed by the Forgejo community with a commitment to 100% free software. Feature-for-feature they're nearly identical today; the difference is governance. For a self-hosted setup with no commercial interest, Forgejo's model is cleaner.

Key Features for Agent Workflows

Resource Usage

~100โ€“150MB RAM idle in Docker. Lightweight enough for a Raspberry Pi 4 (with some patience). A dedicated machine or your always-on GPU rig handles it trivially.

Cons

Option 4: Gitolite

Gitolite is a Perl-based access control layer that sits on top of bare git over SSH. It manages per-repo, per-branch, per-user permissions through a configuration file stored in a git repo itself โ€” meaning access control changes are made by committing to a config repo. It's powerful, battle-tested, and used by large organizations to manage hundreds of repos and users.

For an isolated local AI setup, gitolite adds complexity without much return. The access control features it provides are unnecessary on a trusted private network. The configuration model (a git repo that controls git repos) is elegant but has a learning curve. It has no web UI, no API, and no auto-create on push. Avoid it unless you have a specific need for granular per-branch ACLs.

What to Skip

GitLab CE

GitLab Community Edition is the most feature-complete self-hosted option โ€” and the most demanding. It requires a minimum of 4GB RAM just to run, often needs 8GB+ for reasonable performance, and has a complex multi-process architecture (Rails, Sidekiq, Puma, Nginx, Redis, Postgres, Gitaly). For a local AI lab, this is a data center product being asked to do a simple job. The maintenance burden alone disqualifies it.

Gogs

Gogs is the original lightweight Go git server that inspired Gitea. It's less actively maintained now and has fallen behind both Gitea and Forgejo in features and security patches. No compelling reason to choose it over Forgejo today.

Ollama-style "just use the hosted thing"

If you're running a completely air-gapped network, GitHub isn't an option by definition. But it's worth noting that if your isolation is partial (no sensitive data but LAN-only preference), GitHub remains a zero-maintenance option for the git layer and may be worth keeping for non-sensitive repos while running a local server for sensitive ones.

The Verdict: Two Tiers

OptionInstallRAMAPIAuto-create reposWeb UIBest for
Soft ServeSingle binary~10MBREST (basic)โœ… YesSSH TUI onlyAgent-primary, terminal teams
ForgejoDocker Compose~120MBREST (GitHub-compatible)โœ… Yesโœ… FullHuman + agent mixed workflows
Bare Git + SSHNothing0MBNoneโŒ ManualNoneFixed repo sets, one admin
GitolitePerl + config~5MBNoneโŒ ManualNoneComplex per-branch ACLs
GitLab CEComplex multi-process4โ€“8GB+REST (full)โœ… Yesโœ… FullEnterprise teams

For a local AI agent setup on an isolated network, the answer is one of two things depending on your needs:

Setup: Soft Serve in 5 Minutes

# Install (Debian/Ubuntu)
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://repo.charm.sh/apt/gpg.key | sudo gpg --dearmor \
  -o /etc/apt/keyrings/charm.gpg
echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" \
  | sudo tee /etc/apt/sources.list.d/charm.list
sudo apt update && sudo apt install soft-serve

# Set your admin SSH key and start
export SOFT_SERVE_INITIAL_ADMIN_KEYS="$(cat ~/.ssh/id_ed25519.pub)"
export SOFT_SERVE_DATA_PATH=/var/lib/soft-serve
soft serve &

# Browse your repos from any machine on the LAN
ssh yourserver -p 23231

# Clone a repo (creates it on first push)
git clone ssh://yourserver:23231/myproject
git remote add origin ssh://yourserver:23231/new-agent-project
git push origin main  # repo created automatically

To run as a persistent service:

# /etc/systemd/system/soft-serve.service
[Unit]
Description=Soft Serve Git Server
After=network-online.target

[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/soft serve
Environment=SOFT_SERVE_DATA_PATH=/var/lib/soft-serve
EnvironmentFile=-/etc/soft-serve.conf

[Install]
WantedBy=multi-user.target
sudo systemctl enable --now soft-serve

Add an AI agent's SSH public key:

# Via SSH command (as admin)
ssh yourserver -p 23231 user create agent-codex --admin=false
ssh yourserver -p 23231 user add-pubkey agent-codex "ssh-ed25519 AAAA..."

Setup: Forgejo in 10 Minutes (Docker Compose)

# docker-compose.yml
services:
  forgejo:
    image: codeberg.org/forgejo/forgejo:latest
    container_name: forgejo
    restart: always
    ports:
      - "3000:3000"   # Web UI (optional, skip if agents-only)
      - "2222:22"     # SSH
    volumes:
      - ./data:/data
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - FORGEJO__server__DOMAIN=gitserver.local
      - FORGEJO__server__SSH_DOMAIN=gitserver.local
      - FORGEJO__server__SSH_PORT=2222
      - FORGEJO__database__DB_TYPE=sqlite3
docker compose up -d
# First run: visit http://yourserver:3000 and complete setup wizard
# Or configure headlessly via app.ini in ./data/gitea/conf/

Agent SSH clone pattern:

git clone ssh://git@yourserver:2222/agent-user/repo.git

Use Forgejo's API from an agent:

# List all repos
curl http://yourserver:3000/api/v1/repos/search \
  -H "Authorization: token YOUR_API_TOKEN"

# Create a new repo
curl -X POST http://yourserver:3000/api/v1/user/repos \
  -H "Authorization: token YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"new-experiment","auto_init":true}'

Security on an Isolated Network: What You Can Relax

Standard git server security guidance is written for internet-facing deployments where the threat model includes external attackers, credential brute force, and supply chain attacks. On a completely isolated LAN, most of that threat model doesn't apply.

What you can reasonably relax:

What still matters even on an isolated network:

๐Ÿ’ก The Simplest Backup For Soft Serve: rsync -av /var/lib/soft-serve/ backup-server:/backups/soft-serve/ on a cron. For Forgejo: same with ./data/. SQLite databases are single files โ€” trivial to snapshot. No backup tooling required.

References

  1. Charmbracelet โ€” Soft Serve GitHub Repository โ€” The official source for Soft Serve documentation, installation, and features. โ†— github.com/charmbracelet/soft-serve
  2. Forgejo โ€” Official Site and Documentation โ€” Community-governed Gitea fork. Installation guides, API docs, and comparison with upstream. โ†— forgejo.org
  3. Charm.land โ€” Self-Hosted Soft Serve Guide โ€” Official guide to running Soft Serve with HTTPS and SSH on a self-hosted server. โ†— charm.land
  4. Soft Serve Systemd Integration โ€” Official service unit file and configuration documentation for running Soft Serve as a managed system service. โ†— github.com/charmbracelet/soft-serve/blob/main/systemd.md