Research Concept: VM-Isolated Git-Native Agent Swarm for Code Production

Summary

Run many independent coding agents, each in its own VM, coordinated through Forgejo and NATS — not through multi-agent chat.

  • Forgejo is the shared context: issues define work, PRs deliver it, comments record decisions.
  • NATS/JetStream is the control plane: events, leases, heartbeats, retries.
  • Bluefin VMs provide hypervisor-level isolation with a GNOME desktop for future xRDP/VNC human attach.
  • Copilot CLI is the code-producing engine inside each VM.
  • gitagent (v0.2.0, spec-stage) defines each agent’s identity, skills, and rules as a portable git repo.

Feasibility verdict

The individual components are proven: NATS, Forgejo, VM isolation, Copilot CLI’s programmatic mode, and cloud-init all work today. The main integration risks are (1) bridging Copilot CLI’s GitHub-native tooling to Forgejo, which requires a custom MCP server or context pre-fetch — solvable but not off-the-shelf, (2) building the nats-agent sidecar and Forgejo adapter, which are the two pieces of novel software in the design, and (3) task decomposition — someone or something must break work into single-PR-sized units before agents can consume it. None of these are research problems; they are engineering work with known boundaries. A single-agent end-to-end prototype (one VM, one issue, one PR) is achievable in days. Scaling to a pool of concurrent agents is achievable in weeks.

Key Learnings So Far

  1. Do not build a controller-agent with subagents as the primary control model.
    Instead, run many independent coding agents, each isolated in its own VM.

  2. Use Forgejo as the semantic context substrate.
    Shared context lives in issues, tasks, comments, branches, and PRs — durable, inspectable, resumable, and aligned with software delivery. Forgejo stores meaning; NATS moves attention.

  3. Decompose work before dispatching it.
    Agents perform best on tasks that are repo-scoped, branch-scoped, and reviewable in one PR. A human or a planning step must break larger goals into these units before agents can consume them.

  4. Treat the coding model as a worker engine, not the governor of the system.
    GitHub Copilot CLI can be the main code-producing runtime, but system state must remain externalized. Note: Copilot CLI is GitHub-native — its built-in gh and GitHub MCP integrations do not work with Forgejo. The sidecar must bridge Forgejo operations via MCP or shell tools.

  5. Use gitagent as the agent identity format, not as the orchestrator.
    gitagent separates agent identity, skills, rules, and hooks from runtime execution. Its spec is a git-native, framework-agnostic convention with export adapters for Claude Code, OpenAI, CrewAI, Cursor, etc.

Design Goals

  • Strong isolation: one agent per VM (enforced by hypervisor boundary, not container namespace)
  • Git-native context: work represented through Forgejo artifacts
  • Deterministic coordination: event-driven control plane, not prompt-driven orchestration
  • Portable agent definitions: identity, rules, skills, and hooks versioned in git
  • Human governance: approvals, review, merge control, and live intervention
  • Scalable parallelism: many agents operating concurrently on bounded tasks
  • VM lifecycle automation: a provisioner (libvirt, KubeVirt, or cloud API) must create, recycle, and destroy VMs — this is a prerequisite, not an afterthought

System Architecture

VM Agent

VM Agent

Central Control Plane

webhooks / API

webhooks / API

HTTPS/API

HTTPS/API

secure NATS connection

secure NATS connection

NATS

Core\nevents · request/reply · notifications

JetStream\ntask queue · retries · durable history · leases

Artifact Store\nlogs · transcripts · patches · test results

Human UI\ndashboards · approvals · links · attach

Forgejo Adapter\nbidirectional webhook/API bridge

Forgejo

Bluefin OS\nFedora Atomic + GNOME\ncloud-init bootstrap

nats-agent sidecar\nNKey auth

workspace manager

gitagent repo definition

Copilot CLI runtime\nvia ACP

policy guardrails

Forgejo MCP server / client

Bluefin OS\nFedora Atomic + GNOME\ncloud-init bootstrap

nats-agent sidecar\nNKey auth

workspace manager

gitagent repo definition

Copilot CLI runtime\nvia ACP

policy guardrails

Forgejo MCP server / client

Core Components

1. VM Image: Bluefin OS + Homebrew

Use Bluefin as the base image. Bluefin is an immutable OCI image built on Fedora Atomic (Silverblue) with GNOME, Homebrew, and developer tooling. The desktop environment is a deliberate choice: it enables future xRDP/VNC sessions for human visual attach-to-agent, and allows agents that need browser or GUI-based tools.

The VM image should contain (via Homebrew, rpm-ostree overlay, or baked into a custom OCI layer):

  • git, Forgejo-compatible API client (e.g. tea or direct REST/SDK)
  • nats CLI and/or embedded Go/Rust client library
  • GitHub Copilot CLI (copilot binary)
  • build/test toolchains commonly required for target repos (via Homebrew or Distrobox)
  • xRDP or VNC server (for future human attach)
  • observability agent
  • bootstrap scripts

Rationale:

  • immutable, rpm-ostree-based image with bootc atomic updates
  • developer-friendly tool installation via Homebrew (Bluefin ships brew out of the box)
  • GNOME desktop enables visual remote sessions for human-in-the-loop intervention
  • cloud-init must be layered (rpm-ostree install cloud-init) or baked into a custom OCI image — it is not included in Bluefin by default

2. cloud-init Bootstrap

cloud-init should transform a generic Bluefin image into a task-capable agent node on first boot.

Responsibilities:

  • install/update runtime packages (via brew or rpm-ostree install)
  • fetch short-lived credentials (from a secrets backend such as Vault or a NATS JWT credential issuer)
  • configure NATS endpoint, TLS trust roots, and NKey or JWT-based auth
  • clone or hydrate agent definition repo
  • register agent with control plane
  • enable and start nats-agent.service
  • optionally configure xRDP/VNC for remote attach
  • optionally preload repo mirrors/caches

3. gitagent Definition per Agent

Represent each agent as a git repo using gitagent conventions:

  • agent.yaml — manifest, model preferences, skills, runtime metadata
  • SOUL.md — core identity
  • RULES.md — non-negotiable constraints
  • skills/ — reusable task capabilities
  • hooks/bootstrap.md and hooks/teardown.md — startup/shutdown lifecycle
  • optional knowledge/, tools/, agents/ directories

This aligns with gitagent’s design: agent definitions are git-native, framework-agnostic, and portable across runtimes, with explicit support for hooks, skills, sub-agent declarations, and runtime metadata (see spec).

Important architectural choice: in this system, gitagent defines agent identity and policy, while runtime orchestration remains in infrastructure. The gitagent export --format system-prompt command can produce a flat system prompt from the repo, which is how the sidecar feeds identity into Copilot CLI at task start.

4. nats-agent Sidecar

Each VM runs a lightweight local daemon, nats-agent, responsible for:

  • subscribing to task subjects
  • acquiring task leases
  • reporting heartbeats and lifecycle status
  • materializing workspaces
  • launching the coding runtime
  • publishing artifacts and status
  • handling pause/cancel/attach commands

This sidecar is the VM’s control-plane interface. It is not an LLM; it is deterministic software. On task failure (bad code, context exhaustion, test timeout), the sidecar must:

  • post a structured failure comment to the Forgejo issue
  • publish agent.task.blocked with a reason code
  • either retry with a narrower scope or release the lease for human triage

5. Coding Runtime

The primary code-producing runtime is GitHub Copilot CLI, run inside the VM against a bounded workspace. Copilot CLI supports a programmatic interface (copilot -p "..." --allow-all-tools) suitable for headless invocation, custom instructions files, MCP servers, and custom model providers (OpenAI-compatible, Anthropic, or local Ollama). It also exposes an ACP (Agent Client Protocol) server, which provides a clean machine-to-machine interface for the sidecar.

The sidecar should provide to each invocation:

  • the assigned Forgejo issue/PR context (injected via MCP server or custom instructions)
  • explicit path constraints (via trusted directories)
  • acceptance criteria and test commands
  • PR/commit conventions
  • tool allow/deny policy (--allow-tool, --deny-tool)
  • escalation policy

GitHub dependency caveat: Copilot CLI’s built-in tools assume GitHub.com (e.g. gh commands, GitHub MCP server). For Forgejo integration, existing projects can bridge the gap: forgejo-mcp provides an MCP server for Forgejo, and forgejo-cli provides a command-line client analogous to gh. The sidecar can register forgejo-mcp as an MCP server for Copilot CLI, or pre-fetch issue/PR context into files. Copilot CLI’s COPILOT_PROVIDER_* env vars allow swapping to a self-hosted model endpoint, decoupling from GitHub’s API entirely — but the copilot binary itself still requires a GitHub Copilot subscription.

6. Forgejo Adapter

The Forgejo Adapter is a stateless bridge between NATS and the Forgejo API. It is novel software that must be built. Responsibilities:

  • receive Forgejo webhooks (issue created, PR updated, review submitted) and publish corresponding NATS events
  • subscribe to NATS subjects (agent.task.completed, human.approval.requested) and write comments/labels/status back to Forgejo
  • translate between Forgejo’s REST/webhook model and the NATS subject namespace

7. Forgejo as Shared Context

Forgejo is the system’s semantic memory. Use it for:

  • Issues/tasks: task contract, scope, dependencies, acceptance criteria
  • Comments: progress, handoff, blocking conditions, human decisions
  • Branches/commits: implementation lineage
  • PRs: implementation proposal, diff discussion, review, CI, merge readiness
  • Labels/projects/checklists: explicit workflow state

Operational Model

Task Lifecycle

  1. Human or system creates a Forgejo issue/task
  2. Control plane emits NATS event for eligible agents
  3. One VM agent acquires lease via JetStream KV (TTL-based key as distributed lock)
  4. Agent loads Forgejo context and local agent definition
  5. Agent creates branch/workspace and runs coding task
  6. Agent pushes commits and opens/updates a PR
  7. Agent writes structured status back to Forgejo
  8. Human reviews or intervenes if required
  9. PR merges, task closes, VM cleans up or returns to idle pool

Context Rehydration

A replacement agent must be able to recover from:

  • issue body
  • task checklist
  • comments
  • linked PRs
  • branch state
  • CI status
  • artifacts referenced from comments

This is why Forgejo is the canonical shared context.

Control Plane Data Split

Forgejo

Use for durable, human-readable state:

  • objectives
  • design notes
  • blockers
  • review outcomes
  • merge intent

NATS / JetStream

Use for machine coordination:

  • agent.task.ready
  • agent.task.claimed — acquire via JetStream KV with TTL as distributed lease
  • agent.task.heartbeat
  • agent.task.blocked
  • agent.task.completed
  • repo.pr.updated
  • human.approval.requested
  • human.approval.granted

Agent authentication to NATS should use NKey or decentralized JWT auth with per-agent subject permissions.

Object/Artifact Storage

Use for:

  • long transcripts
  • logs
  • test outputs
  • patch bundles
  • generated reports

Engineering Constraints

Isolation

  • one agent per VM
  • separate credentials per VM or agent class
  • egress restrictions where possible
  • no shared mutable workspace between agents

Task Shape

Best results come from tasks that are:

  • repo-scoped
  • branch-scoped
  • reviewable in one PR
  • bounded by explicit acceptance criteria

Conflict Control

To reduce PR collisions:

  • partition work by path or component ownership
  • use issue dependencies
  • gate concurrent modification of critical paths
  • reconcile through PR review, not agent chat

Example Agent Repo Shape

my-coder-agent/
├── agent.yaml
├── SOUL.md
├── RULES.md
├── hooks/
│   ├── bootstrap.md
│   └── teardown.md
├── skills/
│   ├── forgejo-pr/
│   ├── bounded-refactor/
│   └── test-triage/
├── knowledge/
│   └── repo-conventions.md
└── tools/
    └── forgejo-api.yaml

Example cloud-init Responsibilities

# conceptual only — cloud-init user-data
#cloud-config
users:
  - name: agent
    groups: [sudo, docker]
    shell: /bin/bash

write_files:
  - path: /etc/nats/nats-agent.conf
    content: |
      server: nats://control-plane.example.com:4222
      creds: /etc/nats/agent.creds

runcmd:
  - brew install nats-io/nats-tools/nats
  - curl -fsSL https://cli.github.com/copilot/install.sh | sh  # install Copilot CLI
  - /opt/agent/bootstrap/fetch-secrets.sh
  - git clone https://forge.example.com/agents/my-coder-agent.git /opt/agent/definition
  - /opt/agent/bootstrap/register-with-control-plane.sh
  - systemctl enable --now nats-agent.service

Feasibility Assessment

Strongly Feasible

  • VM-per-agent isolation
  • NATS/JetStream as coordination backbone
  • Forgejo-driven context and collaboration
  • gitagent as portable agent definition format
  • cloud-init bootstrapping on Bluefin (requires layering cloud-init into the image)

Primary Risks

RiskSeverityMitigation
nats-agent sidecar and Forgejo Adapter are novel softwareHighThese are the two core components that must be built. Scope Phase 1 to a single-agent loop to validate interface contracts before scaling.
Copilot CLI assumes GitHub.com, not ForgejoMediumforgejo-mcp and forgejo-cli exist; the remaining work is registering them as Copilot CLI MCP/tool providers, not building a Forgejo bridge from scratch.
No task decomposition step definedMediumProcedural, not technical: require a human or planning step to break work into single-PR issues before dispatch. Enforce via issue templates and label gating.
Copilot CLI requires a GitHub Copilot subscriptionMediumThe copilot binary needs a paid subscription regardless of model provider. If licensing becomes a constraint, the runtime can be swapped for another agentic CLI (e.g. Claude Code, OpenCode) since the sidecar interface is runtime-agnostic.
Merge conflicts across concurrent agentsLowMitigated by path/component partitioning, issue dependencies, and critical-path gating already specified in the design.
gitagent is v0.2.0 with ~10 contributorsLowThe spec is simple enough to fork or inline if the project stalls.
cloud-init not in Bluefin by defaultLowLayer via rpm-ostree install cloud-init or bake into custom OCI image.

Recommendation

Proceed with a Phase 1 prototype using:

  • Bluefin base image (with GNOME for future xRDP/VNC attach)
  • cloud-init bootstrap
  • one nats-agent sidecar implementation with NKey auth
  • Forgejo issue/PR templates
  • gitagent repo format for agent definitions
  • Copilot CLI as the primary coding runtime (with ACP server as the sidecar integration point)
  • SSH, cockpit, or xRDP/VNC as the attach/debug interface for live human intervention

This approach is technically coherent and aligns the system with the actual unit of software delivery: issues, branches, PRs, and reviews, not hidden multi-agent chat state.