How to build a software factory with Claude Code
Step by step: a repository rules file, a GitHub Actions workflow that runs Claude Code, branch protection, a review gate, and status back to the ticket.
Seif Sgayer, Founder
Updated 9 min read
In one line
Everything runs inside GitHub. The agent writes the first draft and never merges.
On this page
This guide builds a small software factory on one repository: a ticket is labelled or moved, a GitHub Actions workflow runs Claude Code in a clean runner, the agent opens a pull request, CI tests it, and a person on your team approves the merge. Everything runs inside GitHub, with the ticket tool of your choice on the front end. There is nothing to buy and about a day of work to do.
It is deliberately a light factory. The agent writes the first draft and never merges. If you want the reasoning behind that choice, read light and dark software factories after this one.
Prerequisites
You need a few things in place before the loop is worth wiring. Skipping them produces a factory that opens pull requests nobody trusts.
- A GitHub repository with a test suite that runs in CI on every pull request, and a one-line command to run it locally. If the tests are flaky, fix that before anything else: the agent will treat a flaky failure as a bug and chase it.
- A Claude plan or API key with access to Claude Code. The agent's usage is billed by Anthropic, so read Anthropic's pricing page and set a budget before you let anything run unattended.
- GitHub Actions minutes. The workflow runs on GitHub's hosted runners, and a Claude Code run takes longer than a normal CI job. GitHub's Actions billing page explains the free allowance and the per-minute rates.
- Branch protection on the main branch requiring at least one approving review, and the ability to add a required status check.
- Tickets with written acceptance criteria. Three short bullet points per ticket is enough. This is the specification the agent works from.
- If you want a ready-made sample to run before adapting your own repository, the free software factory starter includes a sample ticket, setup steps, one reusable skill and a test checklist.
In this build the ticket tool is GitHub Issues, because the trigger and the status update are then a few lines of workflow. Jira, ClickUp and Linear work the same way through their GitHub integrations or a webhook, with a little more plumbing.
The steps
- Write the repository rules file. Create a CLAUDE.md at the root of the repository that states how to install, how to run the tests, the conventions the team enforces, and the paths the agent must never touch. Keep it short and factual. This file is read on every run and is the single biggest lever on result quality.
- Add a trigger label. Create a label on the repository, for example factory, and agree with the team that applying it to an issue means "the factory may pick this up". Only people with triage permission can apply labels, which is your first access control.
- Store the API key as a repository secret. Add your Anthropic API key as an encrypted secret in the repository settings. It never appears in the workflow file or in logs. Scope the GitHub token the workflow uses to the minimum: write on contents, pull requests and issues, nothing else.
- Create the GitHub Actions workflow. Add a workflow file that runs when an issue is labelled with the trigger label. It checks out the repository, runs the official Claude Code action with the issue title and body as the task, and asks the agent to work on a new branch and open a pull request referencing the issue. The skeleton is in the next section.
- Install Claude Code's GitHub integration. Follow the setup in the Claude Code GitHub Actions documentation to connect the app to the repository and confirm the action can comment on issues and open pull requests. Run the workflow once on a trivial issue to see it end to end.
- Protect the main branch. Require one approving review and make the CI test job a required status check. The agent's pull request now cannot merge until the suite passes and a person approves it, whatever the agent does.
- Send status back to the ticket. Add a step that comments on the issue with the pull request link when the run finishes, and a second workflow on pull_request closed that comments and closes the issue when its pull request merges. If your tickets live in Jira or ClickUp, replace the comment with a call to their API or let their GitHub integration do it.
- Measure and tighten. Track tickets turned into pull requests, check pass rate, time from label to pull request, and AI spend per pull request. Use the first weeks to improve the rules file and the tickets, not to loosen the gate.
The repository rules file
Claude Code reads a CLAUDE.md file from the repository root at the start of every run. Treat it as the onboarding document you would hand a careful contractor on their first morning. It should answer, in order: how do I install and run this, how do I run the tests, what conventions must I follow, and what must I never change.
- Setup and test commands, exactly as they are typed. Not "run the tests" but the command itself.
- Conventions the linter does not catch: naming, where new modules go, how errors are handled, what a commit message looks like.
- Definition of done for a factory ticket: tests added or updated, lint clean, pull request description summarising the change and listing the acceptance criteria it meets.
- Forbidden areas: migrations, billing code, authentication, anything with a compliance owner. State the paths. The agent should say in the pull request when a ticket cannot be completed without touching them.
- Scope rules: one ticket, one pull request, no drive-by refactors, no dependency changes unless the ticket asks for them.
Resist the urge to write a long document. A rules file the team actually maintains beats a thorough one that goes stale. When the agent gets something wrong twice, add one line. That is how the file should grow.
The GitHub Actions workflow
The workflow below is a skeleton, not a copy-and-paste solution. Action names, input names and recommended permissions change, so check the Claude Code GitHub Actions documentation for the current version and inputs before you use it. Placeholders are in angle brackets. No secret is ever written into the file.
# .github/workflows/factory.yml (skeleton, check the docs for current inputs)
name: factory
on:
issues:
types: [labeled]
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
jobs:
run:
if: github.event.label.name == '<trigger-label>'
runs-on: ubuntu-latest
timeout-minutes: <limit>
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Run Claude Code on the issue
uses: anthropics/claude-code-action@<version>
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: |
Work on issue #${{ github.event.issue.number }}.
Title: ${{ github.event.issue.title }}
Follow CLAUDE.md. Create a branch, make the change,
run the tests, and open a pull request that references
the issue and lists the acceptance criteria it meets.
# Tool and turn limits go here. Keep them tight at the start.
- name: Report back to the issue
if: always()
run: |
gh issue comment ${{ github.event.issue.number }} \
--body "Factory run finished: ${{ job.status }}. See the linked pull request."
env:
GH_TOKEN: ${{ github.token }}Three details matter more than the rest. The if condition means the workflow does nothing for any other label, so the factory can only be started on purpose. The timeout caps how long a confused agent can run, and therefore how much it can spend. And the permissions block is the whole of what the agent can do to the repository: it can push a branch and open a pull request, and it cannot merge, because merging is governed by branch protection, not by the token.
Run it once on an issue you do not care about, for example "add a comment to the README explaining the test command". Watch the run log, read the pull request, and fix whatever the agent misunderstood by editing the rules file, not the prompt.
Branch protection and the review gate
The review gate is the part of the factory that keeps a person responsible for the main branch. In GitHub it is a branch protection rule, or a ruleset, on main with three settings: require a pull request before merging, require at least one approving review, and require the test job to pass as a status check. Turn off the ability for administrators to bypass it, or at least agree that nobody uses that ability for factory pull requests.
Review an agent's pull request the way you would review a new team member's: read the diff, read the test, and ask whether the acceptance criteria are actually met rather than whether the code looks plausible. Agents are good at plausible. If a pull request needs more than a small change, close it, improve the ticket or the rules file, and run again. Rewriting the agent's work by hand in the pull request trains nothing.
Keep every change approved by a person for as long as it takes to trust the suite. Later, for low-risk classes of work such as dependency bumps or copy fixes, you can allow auto-merge on green. That is a decision to make when the tests have earned it, not a default.
Status back to the ticket
A factory that does not report back creates a new chore: checking GitHub to find out what happened to a ticket. Close the loop. The run comments on the issue when it finishes, with the pull request link or the failure. A second workflow, triggered when a pull request closes, finds the issue it references and closes it when the pull request was merged, or comments when it was closed without merging.
With Jira or ClickUp as the front end, the shape is the same. Their GitHub integrations move a ticket when a branch or pull request references its key, and both have APIs for anything the integration does not cover. Whichever tool you use, the test is simple: a product manager should be able to follow a ticket from backlog to done without opening GitHub.
What to measure
Measure from the first run, because the early numbers tell you where to spend effort. Four figures are enough to start, and all of them can be read from GitHub and your provider's usage page without a dashboard.
| Measure | Where it comes from | What it tells you |
|---|---|---|
| Tickets turned into pull requests | Issue label events against pull requests opened | Whether tickets are specified well enough for the agent to finish |
| Check pass rate | Status check results on factory pull requests | Whether the rules file and the suite are doing their job |
| Time from ticket to pull request | Label timestamp to pull request timestamp | Where the queue is: runner, agent, or waiting for review |
| AI spend per pull request | Provider usage against pull requests merged | Whether the loop is worth running for this class of work |
Do not set targets for these in the first month. Watch them, improve the tickets and the rules file, and widen the kinds of work you label only when the pass rate on the current kind is boring.
This guide is the same loop we set up for client teams at HorizonLux, the studio behind this service, so the steps above are the ones that survive contact with a real backlog.
Teams that would rather not spend the day on the plumbing can have the same loop built inside their own tools: that is our software factory setup service, and it starts with one repository and one workflow.
Common questions
Can Claude Code run in GitHub Actions without a person present?
Yes. The official Claude Code GitHub Action runs on a hosted runner in response to an event such as an issue being labelled, with the API key held as a repository secret. The agent can push a branch and open a pull request. Merging stays under branch protection, so a person still approves what lands.
Do I need Jira or ClickUp to build a software factory?
No. GitHub Issues works as the ticket tool and makes the trigger and the status update a few lines of workflow. Teams that already run Jira, ClickUp or Linear keep them and connect through the GitHub integration or a webhook. The loop is the same; only the plumbing at each end changes.
What does a Claude Code software factory cost to run?
Three costs, all paid to the providers directly: Claude usage billed by Anthropic, GitHub Actions minutes on hosted runners, and the tools you already pay for. Set a timeout and tool limits on the workflow so a confused run cannot spend without bound, and track AI spend per merged pull request from the start.
How do I keep the agent out of sensitive code?
Name the forbidden paths in the repository rules file and tell the agent to stop and report when a ticket needs them. Back that with a CODEOWNERS file so those paths always require a named reviewer, and keep the workflow token scoped to branches and pull requests. Branch protection does the rest.
More guides
The other four notes in this series.
Get your software factory set up
We start with one repository and one workflow. Once it works, we add more.