Skip to content

projectsagent-factory.md

Agent factory

A self-hosted VPS for building, testing and deploying apps with coding agents.

Open Forgejo

Overview

A Netcup VPS running Coolify for deployments, Forgejo for Git and CI, and Hermes as the coding agent. PostgreSQL, an isolated Actions runner and Tailscale support the setup, which is kept separate from my personal machines and data.

Server and setup details

The server

Netcup VPS:

  • 8 shared CPU cores
  • 16 GB RAM
  • 320 GB SSD
  • Debian 13
  • IPv4 and IPv6

About €12 a month. The CPU is shared, which is fine for experiments, small apps, and one CI job at a time.

The server is deliberately separate from my personal machines and data. Agents make mistakes, so I'd rather give them a disposable VPS than my Mac.

The stack

  • Coolify for deployments
  • Forgejo for Git hosting
  • Forgejo Actions for CI
  • Hermes Agent for the coding agent
  • PostgreSQL for Forgejo
  • Tailscale for private administration

Public addresses:

A wildcard DNS record points *.factory.jwhardwick.dev at the VPS, which makes adding more apps later easy.

Coolify

Coolify manages the Docker services and HTTPS certificates. It also gives me a way to deploy apps without handing the agent unrestricted SSH access.

The Coolify dashboard stays private. I reach it on port 8000 over Tailscale; the direct management ports are blocked from the public internet:

6001
6002
8000
8080

Public HTTPS for apps goes through Coolify's Traefik proxy.

Forgejo and CI

Forgejo stores the repositories. I added one Forgejo Actions runner using Docker-in-Docker.

The runner doesn't use the host Docker socket. Access to /var/run/docker.sock is effectively root on the box, so jobs run inside a separate Docker daemon:

services:
  docker-in-docker:
    image: docker:dind
    privileged: true
 
  runner:
    image: data.forgejo.org/forgejo/runner:13
    environment:
      DOCKER_HOST: tcp://docker-in-docker:2375

One CI job at a time to start. Sixteen gigabytes is enough for the current stack, but a few builds running together would eat it fast.

I tested the runner with a private repo and a small workflow:

name: smoke
 
on:
  push:
    branches: [main]
 
jobs:
  verify-runner:
    runs-on: docker
    steps:
      - name: Check the runner
        run: |
          node --version
          echo "Forgejo Actions runner works"

It ran, so the Git and CI path works.

Hermes

Hermes runs as a Coolify service with a persistent home directory and workspace. It uses OpenRouter for models, with a dedicated key that has a small spending limit instead of my main one.

Hermes has two restricted API credentials:

  • A Forgejo token for a dedicated hermes-agent user
  • A Coolify token with read, write, and deploy permissions

The Forgejo account is only a member of the factory organisation. The Coolify token can't read sensitive values and has no root permission.

Two local skills handle factory work:

forgejo-cli
coolify-api

The Coolify skill asks before changing anything — read-only calls work normally, mutations need a --yes flag, and it supports dry runs.

I tested all three parts separately:

HERMES_FACTORY_OK
FORGEJO_INTEGRATION_OK
COOLIFY_SKILL_OK

That confirmed model access, Forgejo access, and Coolify access.

Network access

Public ports:

22      SSH
80      HTTP redirects and certificate setup
443     HTTPS
22222   Forgejo Git over SSH

Coolify's management ports are blocked on the public interface; Tailscale is the private route for administration. SSH password auth is off — keys only.

Backups

Netcup snapshots are useful but I don't treat them as backups. A provider or account problem could take out the server and its snapshots together.

Off-server backup, stored on my FileVault-encrypted Mac:

  • Coolify's PostgreSQL database
  • Forgejo's PostgreSQL database
  • Forgejo repositories and configuration
  • Hermes state and workspace
  • Runner configuration
  • Coolify configuration

Initial resource use

With Coolify, Forgejo, PostgreSQL, Hermes, and the runner running:

RAM:  2.1 GB of 15 GB
Disk: 19 GB of 314 GB

This initial setup left room for small apps. Firecrawl was not included; its browser workers can use more memory.

Motivation

I wanted a disposable place for agents to build and break things without touching the rest of my infrastructure. An old i7 desktop died mid-setup, so I rented a VPS instead; it was easier to manage and gave me a cleaner boundary.

Inspired by Jake Saunders' self-hosted agentic software factory.

Check it out

Open Forgejo to browse the repositories. For a similar setup, start with a Debian VPS, deploy Coolify and Forgejo, add an isolated Actions runner, then configure Hermes with scoped credentials. The intended workflow takes a small app idea through a repository, application code, tests and CI, and deployment through Coolify. Administration stays private over Tailscale.

Open Forgejo