Agent Forge is a clean starting point for creating and operating dedicated
simple-coding-agent instances
for GitHub repositories. It follows the same workflow as the sibling
../simple-coding-agent-env project: create an agent with create-agent, build
its Docker image, start it with Docker Compose, change its Workers with
manage-pool, and investigate problems with debug-agent.
Each instance targets one repository and has its own toolchain, repository profile and configuration. It runs one or more Workers (containers), each with its own persistent Docker volume. The agent's source is fetched from upstream at build time.
agent-forge/
├── .agents/skills/
│ ├── create-agent/ # Instance scaffolding instructions and templates
│ ├── manage-pool/ # Add, remove, stop and resume Workers of an instance
│ └── debug-agent/ # Diagnostics instructions and helper scripts
├── .claude -> .agents # Exposes the same skills to Claude Code
├── .gitignore
├── CONTEXT.md # Domain glossary (Instance, Worker, Pool, ...)
├── README.md
├── docs/adr/ # Architecture decisions
└── agent-instances/ # Local instances; ignored by Git
└── agent-<name>/
├── Dockerfile
├── compose.yaml # One service per Worker: agent, agent-2..N
├── simple-coding-agent-profile.yml
├── .env.example
├── .env
├── agent-entrypoint.sh # Optional, for bundled services
├── compose.litellm.yaml # Optional, joins every Worker to a LiteLLM gateway network
└── .env.worker-<n> # Optional, a Worker's own GITHUB_TOKEN
Create all instances inside agent-instances/. The entire directory is
ignored by Git, including generated configuration and secrets. There are no
preconfigured instances in this starting version; keep backups of local
configuration separately if needed.
- Docker with BuildKit and Docker Compose v2.17 or newer, for additional build contexts.
- A coding assistant with access to the included skills.
- Access to the target repository and a GitHub token with read/write permissions for its contents, issues, and pull requests.
- The model API credentials required by the generated configuration
(
META_API_KEYfor the default Meta backend; from simple-coding-agent v0.3.2,MODEL_API_KEYwithMODEL_BASE_URL/MODEL_AUTH_MODEselects another backend, see.env.example). Formuse-*modelscreate-agentrecommends a LiteLLM gateway, which restores Meta prompt caching: the gateway runs separately on a shared Docker network, the agent holds only its master key asMODEL_API_KEY, andCOMPOSE_FILEin.envaddscompose.litellm.yamlto attach the agent to that network. Anthropic models connect directly.
Ask your coding assistant to use the
create-agent skill, specifying the
target repository and destination. For example:
Use create-agent to create an agent for https://github.com/owner/repository
in agent-instances/agent-repository/.
The skill inspects the target repository's stack and CI, prepares its Docker toolchain, and writes a local profile containing dependency setup and validation commands. The profile should mirror the repository's gating CI checks. Instances that require services such as MySQL or Redis may also include an entrypoint to start them.
Review the generated .env and supply any missing credentials before starting
the agent. AGENT_SRC_REF selects the upstream agent branch, tag, or commit and
defaults to main. Runtime versions are not pinned per instance: upstream at
AGENT_SRC_REF decides claude-agent-sdk (its pyproject.toml), and the
Claude Code CLI is the one bundled in that SDK release. To upgrade, move
upstream or AGENT_SRC_REF and rebuild; do not set CLAUDE_AGENT_SDK_VERSION
in .env.
Conflict requeue (optional, off by default). When the published pull
request of an issue falls behind its base branch and reports a conflict, the
issue can come back to the Queue on its own instead of waiting for a human.
To enable it, uncomment MAX_CONFLICT_ATTEMPTS in .env and set it to N:
0 (the default) turns the path off entirely, and N is the number of
consecutive failed Conflict attempts on one issue before the Worker escalates
it with the ready-for-human label. A Conflict attempt is cheap: with no
model call, the Worker rebases the issue's agent/issue-N branch onto the
base, runs setup plus one profile check, and force-pushes only when green.
The Queue claims an issue carrying the merge-conflict label ahead of other
work; the Worker applies that label itself when it sees a conflicting branch,
and a human may also apply it by hand with the same effect. After N
consecutive failures the Worker adds ready-for-human and never removes it —
hand the issue back by removing the label, which requeues it with a fresh
budget. The setting is independent of PR_AUTO_MERGE: conflicts block manual
merges too. It needs an upstream agent that contains the feature
(AGENT_SRC_REF v0.6.0 or newer; main tracks upstream).
Pools (several Workers). An instance runs one Worker by default; ask
create-agent for N to get a Pool of N Workers taking issues from the same
Queue. A Pool is one instance and one Compose project, so it runs on one Docker
context with one model backend; Workers on another host or backend are a
separate instance (see docs/adr/0002-one-pool-per-docker-context-without-swarm.md).
In compose.yaml the first Worker is the service agent with the volume
agent_data; further Workers are agent-2..N with the volumes data_2..N.
They share one image, built once by the agent service, and the settings of
the x-worker anchor, including per-Worker limits (1.5 CPUs, 3g memory — an
estimate — and 1024 PIDs) that WORKER_CPUS, WORKER_MEM_LIMIT and
WORKER_PIDS_LIMIT in .env override.
Workers sharing one GitHub login are told apart by their Worker id
(WORKER_ID, <short-name>-<n>, e.g. battles-2), set per Worker in
compose.yaml together with the commit author Claude Code (<worker-id>).
It is set when the instance has two or more Workers or shares its login with
another instance on the same repository; create-agent looks for such an
instance and asks. Worker ids need simple-coding-agent v0.7.0 or newer, and
two or more Workers on one login need v0.9.0 or newer (the startup recovery
fix of lbacik/simple-coding-agent#364). Never run Workers
of different Claim protocol versions on one login: stop and drain every
Worker on the login, upgrade and set WORKER_ID on all of them at once, and
only then add Workers. The create-agent skill describes the order in
references/pools.md; manage-pool carries it out for an existing instance.
Run Compose commands from the instance directory:
cd agent-instances/agent-repository
docker compose config -q
docker compose buildEach instance builds independently. There is no root-level Compose deployment or shared build command. Its repository profile is baked into the image, so profile or Dockerfile changes require a rebuild.
docker compose up -dCheck the container and its startup logs:
docker compose ps
docker compose logs --tail=100 -fThe generated compose.yaml sets init: true so that Docker's init reaps
processes orphaned by the agent's tools; without it, every attempt eventually
fails once the container runs out of process IDs. Instances created before
this setting need init: true added to their agent service, then
docker compose up -d.
The named agent_data volume (data_2..N for further Workers) stores the
working repository, state, and attempt logs under /data in the container.
These persist across container recreation.
After rebuilding an updated image, run docker compose up -d again to apply it.
To stop the deployment:
docker compose downThis preserves the named volumes. Adding -v deletes the volumes of every
Worker and their agent data.
To run an instance with an alternative configuration, such as .env.claude for
the Anthropic API, copy .env, change the differing settings and set
AGENT_ENV_FILE=.env.claude in the copy. Then pass the file to every command:
docker compose --env-file .env.claude build
docker compose --env-file .env.claude up -d--env-file alone replaces .env only for interpolation in compose.yaml;
AGENT_ENV_FILE makes the container load the same file. Both configurations
share the container and the agent_data volume unless you also pass a separate
project name with -p.
An instance that uses a LiteLLM gateway needs no extra flags: COMPOSE_FILE
in its env file makes every docker compose command load
compose.litellm.yaml as well.
Ask your coding assistant to use the
manage-pool skill to change the
Workers of an existing instance. For example:
Use manage-pool to add a Worker to agent-instances/agent-repository on the
rpi5 context.
It covers adding a Worker (on the shared login, or with its own GitHub
account in .env.worker-<n>), removing one, stopping and resuming one Worker
or the whole Pool, and agentctl next issue for a chosen Worker, including
the order above when a login gets its second Worker. Every change waits for
your go-ahead, a Worker holding a Claim is never removed, and volumes are
deleted only by you.
Ask your coding assistant to use the
debug-agent skill. Include the instance,
issue number when applicable, and Docker context if it runs on another host:
Use debug-agent to investigate agent-instances/agent-repository.
Check the latest run for issue #42 on the orbstack context.
The skill examines startup logs, persisted state, attempt events, and validation output to identify whether the problem comes from the target repository, the instance configuration, or the upstream agent.
The bundled diagnostic helpers find instances in agent-instances/ from their
own location, so they work from any working directory. For example, from the
project root:
.agents/skills/debug-agent/scripts/locate-agent.sh repository 42They default to the orbstack Docker context; pass --context <name> for another
context.
The skills and templates originate from ../simple-coding-agent-env. They
have been adapted to Agent Forge: every generated deployment goes to
agent-instances/agent-<name>/. The reference instances the skills mention
(for example agent-jsonhub-web-terminal, agent-jsonhub-api) live in the
sibling project and are read from there when it is available.
The operating workflow remains the same:
create-agent → docker compose build → docker compose up -d → manage-pool → debug-agent