# How I turned fstack into a software factory

> How I use fstack, GPT-5.6 Sol, bounded subagents, repository context, and review gates to build many software products without losing control.

Author: [Flavio Copes](https://flaviocopes.com/about/) | Published: 2026-07-29 | Topics: [AI](https://flaviocopes.com/tags/ai/) | Canonical: https://flaviocopes.com/fstack-software-factory/

I recently launched [fstack](https://flaviocopes.com/fstack/), my collection of 13 simple agent skills.

At first I saw it as a better way to work with one coding agent.

Take an idea. Nail it down. Write a plan. Build it. Check the result. Push it.

Then I started using the same system across all the applications I am building under `~/www`.

Some are small static sites. Some have hundreds of generated pages. Some have accounts, databases, payments, background jobs, and private member areas. Some are courses with dozens of lessons and practical templates.

One agent was no longer enough.

I did not want one enormous autonomous agent either.

I wanted a manager that understood the whole product, several workers that could build independent parts, and a strict review step before anything became part of the product.

This changed how I think about fstack.

It is becoming a **software factory**.

Not a magic machine that turns one sentence into a startup.

A factory is a repeatable production system. Work enters in one form, passes through clear stations, gets inspected, and leaves in a better-defined form.

The important part is not that many agents write code.

The important part is that every agent has a job, every job has boundaries, and every result is checked.

## What I mean by a software factory

The phrase can sound bigger than it is.

My software factory is a collection of plain files, agent skills, model roles, and review rules.

The input might be:

- a product idea
- a feature request
- a set of course lessons
- a large content migration
- a framework port
- a redesign
- a bug that touches several systems

The output is not just code.

The output is a working, verified, documented change that still matches the original product decision.

The full line looks like this:

```text
idea or task
  -> challenge and clarify
  -> write the product context
  -> write the plan
  -> split the work
  -> run independent production cells
  -> review every return
  -> integrate
  -> verify the complete product
  -> document what matters
  -> commit, push, and log the outcome
```

There is still a human in this system.

I choose the idea. I answer product questions. I approve the plan. I make the decisions that affect the product. I look at the result and decide whether it is good.

The factory removes repeated implementation work.

It does not remove judgment.

## More agents do not create a factory

It is easy to launch five agents.

That is not the difficult part.

Without structure, five agents can create five different interpretations of the same task.

One changes the data model. One invents a new design system. One edits a shared file another agent is also editing. One adds a library. One finishes early and says everything looks good.

You get more output, but you also get more uncertainty.

This is the difference between **parallel work** and a **production system**.

A production system needs:

- one source of truth
- one owner of the plan
- clear dependencies
- clear file ownership
- repeatable briefs
- visible progress
- review before integration
- proof before completion

I had parts of this before fstack.

fstack gave me the small control points. The multi-agent setup added the production cells. Repository files made the state durable.

Together they became the factory.

## fstack is the control system

fstack still has 13 small skills.

I do not want to replace them with one giant `/fstack-factory` command.

That would recreate the problem I built fstack to avoid. One command would have to understand product strategy, planning, architecture, implementation, design, testing, documentation, and Git.

It would become difficult to inspect and difficult to stop.

Instead, each skill controls one station.

The main production loop is:

```text
fstack-nail -> fstack-plan -> fstack-build -> fstack-check -> fstack-push
```

The other skills support the line:

- `/fstack-roast` challenges the idea before I invest in it
- `/fstack-interview` records the product context
- `/fstack-simplify` removes unnecessary complexity
- `/fstack-design` brings the interface back to the existing design system
- `/fstack-counselors` asks three independent models about a difficult decision
- `/fstack-document` writes and updates the project documentation
- `/fstack-learn` saves one non-obvious lesson for the next session

The `/fstack` skill is the front door. It picks one of the other 12 skills, runs it, and stops.

Stopping matters.

Each station has an exit. I can inspect what happened before sending the work to the next one.

## The factory starts before code

A fast factory can manufacture the wrong thing very efficiently.

This is why the first stations do not write code.

If the product idea is weak, I can run `/fstack-roast`.

It asks questions about the customer, the status quo, demand, distribution, and the smallest version worth building. It ends with one of three verdicts:

- build the wedge
- shrink it
- do not build it

The goal is not to be negative.

The goal is to avoid putting a vague idea on an efficient production line.

For a new project, `/fstack-interview` records the business context in `AGENTS.md`.

The result is short:

```markdown
## Product context

- **Product:** what this is
- **Customer:** who it is for
- **Demand:** what evidence exists
- **Business model:** how it makes money
- **Status quo:** what it replaces
- **Distribution:** how people find it
- **Not doing:** what stays outside the product
- **Open questions:** what we still do not know
```

This file becomes part of the repository.

Every future agent starts with the same product definition. It does not have to reconstruct the business from old chat messages.

This is the first factory rule:

> Long-lived project state belongs in the repository, not in chat memory.

## The plan is the production order

When a task is unclear, `/fstack-nail` asks up to five questions.

Then it reduces the answers to three lines:

- what we are building
- the constraint that matters most
- what success looks like

Once I confirm those lines, `/fstack-plan` writes `PLAN.md`.

Every plan has the same four sections:

```markdown
### What we're doing

The outcome and why it matters.

### Steps

1. A small step that can be completed and verified.
2. Another small step.

### What we're NOT doing

- A tempting extra that is outside this task.
- A future feature we are not building now.

### How we'll know it works

- A concrete behavior we can test.
- A build, test, or browser check that must pass.
```

The most valuable section is often **What we're NOT doing**.

Agents are good at expanding an idea.

They see possible abstractions, settings, fallbacks, dashboards, and future features. Many sound reasonable. Most are not needed for the current result.

The exclusion list gives the factory a physical boundary.

Work outside that boundary does not enter the line.

## GPT-5.6 Sol is the factory manager

I currently use GPT-5.6 Sol as the planner, coordinator, and reviewer.

Opus 5 is also great in this role.

This is where I want the strongest reasoning model I have available.

The manager owns the complete picture.

It reads the request, the codebase, `AGENTS.md`, `PLAN.md`, the design rules, the existing architecture, and the files that define shared contracts.

It decides how to split the work.

It also decides what must *not* be split.

I put the coordination rules directly in my repositories:

```markdown
Use GPT-5.6 Sol as the planner, coordinator, and reviewer.

Use Composer 2.5 subagents only for bounded execution or
investigation tasks with clear inputs, constraints, and output format.

Subagents may inspect, report, test, or implement narrow changes.
They may not redefine the plan, change architecture, expand scope,
or touch shared contracts unless explicitly instructed.
```

I can replace GPT-5.6 Sol with Opus 5 and keep the same system.

The model names will change again.

The roles are the important part.

One agent must own the plan. Worker agents must not make product-wide decisions independently.

Using the strongest model as the manager is worth it. A weak plan multiplied across several fast workers creates expensive rework.

The manager usually writes less code than the workers. Its leverage comes from making better decisions, writing better briefs, and rejecting bad returns.

If every worker can change the architecture, there is no architecture.

## Composer subagents are production cells

I use Composer 2.5 subagents for bounded work.

A bounded task has clear inputs and outputs.

It should also be independently verifiable.

Good worker tasks include:

- inspect a set of routes and return a migration inventory
- write three lesson files from an approved curriculum outline
- implement one calculator in its own folder
- port one isolated application using an existing parity contract
- test a group of pages and report every failure
- research one narrow technical decision without changing files

Bad worker tasks include:

- make the product better
- redesign the architecture
- finish whatever is missing
- clean up the codebase
- build the backend while another worker builds against an undefined API

The manager does not delegate confusion.

It resolves the important questions first, then delegates execution.

## Every worker gets a real brief

A vague prompt creates vague work.

Every production cell receives a self-contained brief with five parts:

```markdown
## Goal

One sentence describing the exact outcome.

## Context

The product decisions, relevant files, and constraints the worker
cannot safely infer.

## Deliverables

The exact files to create or change and what each must contain.

## Constraints and boundaries

Files the worker must not touch, decisions it must not make,
and work that stays outside this task.

## Bring back

Files inspected, files changed, tests run, decisions made,
uncertainties, and review points.
```

The last line in every brief is:

> Flag uncertainty; do not guess silently.

This line saves time.

A worker that guesses can produce a polished implementation of the wrong decision. A worker that reports uncertainty gives the manager a useful decision point.

The brief also assumes the worker has no chat history.

Everything it needs must be in the repository or in the brief.

That makes the task reproducible. Another worker can receive the same production order and understand it.

## File ownership makes parallel work possible

Parallel work is useful when tasks do not compete for the same files.

For example, imagine a course with six weeks of material.

The manager can define the curriculum, lesson format, shared layout, and metadata contract first. Then three workers can write weeks 1–2, 3–4, and 5–6 in separate content files.

They can run at the same time because their file sets do not overlap.

The manager integrates the shared course index later.

The same approach works for:

- independent route groups
- separate tools in isolated folders
- content collections
- test suites for unrelated modules
- framework editions in separate package directories
- research tasks that only return reports

I do not run two writing agents against the same shared abstraction.

Two workers editing the same router, schema, config file, or design token file are not parallel. They are a race condition.

The rule is simple:

> Parallelize independent files. Sequence shared contracts.

## The dependency graph comes before the workers

Some work looks independent but is not.

A user interface might depend on a data contract. Tests might depend on a finished migration. Product pages might depend on verified package metadata.

The manager maps those dependencies before launching a batch.

A simple project might look like this:

```text
product contract
  -> data model
    -> API routes
      -> interface
        -> end-to-end tests

product contract
  -> independent content files
  -> independent documentation files
```

Only the branches that do not depend on each other run in parallel.

I also keep a live task list. Every subtask is pending, in progress, returned, accepted, patched, or re-briefed.

This sounds like project management because it is project management.

Agents make implementation faster. They do not make dependencies disappear.

## The manager stays useful while workers run

The factory manager should not launch workers and wait.

While a batch runs, the manager can:

- inspect shared files
- prepare the next briefs
- update the task list
- review a return from an earlier batch
- handle integration work that does not depend on the active workers
- verify the product contract against the current implementation

This keeps the line moving without creating overlapping edits.

If a brief turns out to be wrong, I do not send several corrections while the worker is halfway through the task.

I let the return arrive, review it, then issue a corrected brief.

Mid-flight instructions create work that follows two different plans.

## Every return is inspected

Worker self-reports are useful.

They are not proof.

The manager reads the actual files, checks the diff, and walks through the brief line by line.

Every return gets one of three verdicts:

- **ACCEPT** — the work matches the brief
- **PATCH** — the work has a trivial issue the manager can fix immediately
- **RE-BRIEF** — the approach or deliverable is substantially wrong

The distinction between patching and re-briefing matters.

A missing import is a patch.

A wrong data model is not.

If the manager quietly repairs a large failed delegation, the production system learns nothing. The worker brief remains bad, the boundary remains unclear, and the same failure returns in the next batch.

A corrected brief explains what was wrong and sends the task through the cell again.

After individual reviews, the manager runs a cross-cutting pass.

It checks naming, tone, structure, imports, links, shared types, and duplicated logic across all returned work.

This is how several worker outputs become one product instead of a pile of parts.

## The quality gate has three questions

When the implementation is complete, `/fstack-check` asks exactly three questions.

### Does it work?

The agent must prove it.

That might mean running tests, building the site, opening pages in a browser, submitting forms, checking responsive layouts, or testing a clean installation.

“It should work” is not evidence.

### Does it match the plan?

The finished diff is compared with `PLAN.md`.

The check looks for planned work that is missing and extra work that was never approved.

It also checks the blast radius: routes, callers, styles, data, configuration, and anything else the change could affect.

### Is it simple?

The final pass looks for unnecessary abstractions, unused code, speculative options, duplicated logic, and dependencies that replace a few lines.

If something smells wrong, the check reports it.

It does not fix it automatically.

Review and repair are separate jobs. This keeps the evidence clean.

## Simplification is its own station

`/fstack-simplify` only removes and reduces.

It does not redesign working code. It does not replace one style with another. It does not propose a new framework.

It looks for things such as:

- dead files and exports
- abstractions with one caller
- configuration nobody requested
- dependencies used once
- impossible error handling
- comments that repeat the code
- future features the future never asked for

Then it proposes deletions and tells me what I would lose.

Usually the answer should be: nothing.

The factory can produce too much code very quickly.

A deletion-only station is my counterweight.

## The repository is the factory memory

Chat sessions end.

Models change. Context windows fill. A new agent starts tomorrow without remembering the decision made tonight.

The repository must carry the important state.

I use a few plain files:

- `AGENTS.md` contains product context, architecture rules, and learned preferences
- `PLAN.md` contains the current production order and its boundaries
- `docs/overview.md` explains the product in plain language
- `docs/architecture.md` explains how the parts fit together
- `docs/reference.md` records files, configuration, commands, and environment needs
- `LEARNED.md` stores short lessons that should change future work

`/fstack-document` creates or updates the three documentation layers.

`/fstack-learn` adds one lesson at a time. The entry is at most three lines.

For example:

```markdown
## 2026-07-25 — Parallel file ownership
Never assign two workers to the same shared registry.
Build isolated files first, then let the manager integrate the registry.
```

Routine changes do not belong there.

Only a lesson that can save real time in a future session earns a place.

I also keep a global plain-text work log. A Git `post-commit` hook records each completed outcome, grouped by date and project. I wrote about [how that work log works](https://flaviocopes.com/log-git-commits-plain-text/).

The repository explains the product.

The work log explains what changed across the factory.

## Defaults keep the line moving

I use the same default web stack for most new projects:

- Astro
- HTMX when I need server interactions
- Alpine.js when I need small client-side state
- Cloudflare for deployment

The AHA Stack removes repeated setup decisions.

I do not spend the first hour comparing ten frontend frameworks and five hosting platforms.

For a static site, I might only need Astro.

For a server-rendered product, I can add HTMX, Alpine, D1, authentication, email, or payments as the product requires them.

The default is not a rule that every product must look identical.

It is a known production line.

When the task specifically calls for another stack, I use another line. I have been producing Next.js editions of existing applications because the target is Vercel and the edition itself is the product.

The factory should remove accidental choices.

It should not ignore real requirements.

## What this looks like in my projects

I have been applying this system to very different work under `~/www`.

In one project, I had to build a six-week course with 24 lessons, practical labs, an instructor guide, and 12 operating templates.

The curriculum and lesson contract came first. The content was then divided by week into independent file sets. The manager reviewed every batch, integrated the course navigation, checked the public/private publishing boundary, and ran the complete build.

In another project, I added a field-research layer across hundreds of migration routes.

The factory started with the data schema and validation rules. Research ran route by route. The visible section was integrated only after the reports passed source-type, duplicate, attribution, depth, and date checks.

In another, I planned framework editions for 18 working prototypes.

Before any port began, each prototype received a parity contract covering routes, features, data, authentication, real-time behavior, integrations, and tests.

The projects were divided into cohorts:

- static and browser-heavy products
- standard applications
- infrastructure-heavy applications

Independent editions could run in parallel. Shared baseline decisions came first. Every edition had to pass clean installation, native checks, tests, a production build, package review, and browser checks.

This is where the factory idea became concrete for me.

The work was not “make 18 apps.”

The work was:

1. define what must remain true
2. establish one known baseline
3. divide the products by complexity
4. give each cell a bounded edition
5. inspect every result against the same contract
6. publish only the editions that pass

The same system also works for smaller products.

A site with four pages does not need eight workers. The manager can do the work directly. The factory has no rule saying every task must be delegated.

Delegation has a cost.

The brief must be written. The worker must run. The return must be reviewed. If doing the task directly is faster and clearer, the manager does it.

## The factory does not make every product the same

Factories bring images of identical objects moving down a conveyor belt.

That is not what I want for software.

The products I am building are different.

One is a content library. One is a business application. One is a course. One is a browser tool. One is a visual product. One is a source-code prototype.

They should not share the same interface, data model, or business rules.

What they share is the production method:

- clarify before building
- store context in the repository
- plan before parallelizing
- keep architecture decisions centralized
- assign independent file sets
- require explicit return reports
- inspect artifacts instead of trusting summaries
- verify the complete product
- remove unnecessary complexity
- record what future agents must know

The factory standardizes the **process**, not the product.

## What I do not automate

There are parts I deliberately keep outside the line.

I do not let a worker decide the product direction because it found an interesting feature while reading the code.

I do not let several agents invent public names, pricing, or positioning independently.

I do not let workers change shared data contracts without an explicit brief.

I do not merge a return because its summary sounds confident.

I do not deploy unfinished work because the build passed.

I do not turn uncertainty into guessed code.

And I do not run every fstack skill automatically.

Sometimes I need a plan but not a roast. Sometimes the task is clear and does not need `/fstack-nail`. Sometimes a small change can go directly to checking and pushing.

The line adapts to the work.

## Common factory failures

I have found a few failure modes that appear quickly.

### Too many workers

More workers increase coordination work.

If a project has three independent tasks, launching ten agents does not make it faster. It creates seven agents looking for something to do.

Use the smallest useful batch.

### Weak briefs

“Build the settings area” leaves every important decision open.

A good brief names the pages, data, states, existing patterns, excluded work, tests, and files.

### Shared-file collisions

Parallel workers should not edit the same registry or abstraction.

Give them isolated files. Integrate shared files after the batch.

### Delegated architecture

Workers can investigate architecture options.

They should not each select one.

The manager makes the decision once and puts it in every relevant brief.

### Blind trust

A passing unit test does not prove the page works.

A worker report does not prove the requested file exists.

The final check must match the kind of product being built.

### Chat-only decisions

A decision that exists only in one conversation will be lost.

Move it into `AGENTS.md`, `PLAN.md`, documentation, a test, or the code itself.

### Measuring output instead of value

The factory can generate pages, components, tests, and documentation at impressive speed.

None of that proves someone wants the product.

This is why `/fstack-roast` and the product interview belong at the start.

## How to build this setup yourself

You do not need a large platform.

Start with fstack:

```bash
npx skills@latest add flaviocopes/fstack
```

Then add a short coordination section to the repository's `AGENTS.md`:

```markdown
Use one agent as the planner, coordinator, and reviewer.

Use worker subagents only for bounded tasks with clear inputs,
file boundaries, constraints, and output format.

Workers may not redefine the plan, change architecture,
expand scope, or edit shared contracts unless instructed.

Every worker must return files inspected, files changed,
tests run, decisions made, uncertainties, and review points.

The coordinator reviews the actual artifacts before integration.
Long-lived project state belongs in repository files.
```

For a new product, the workflow is:

1. Run `/fstack-roast` if the idea needs honest pressure.
2. Run `/fstack-interview` to record product context.
3. Run `/fstack-nail` if the first task is unclear.
4. Run `/fstack-plan` and approve `PLAN.md`.
5. Let the manager map dependencies and file ownership.
6. Write one complete brief per worker task.
7. Run independent tasks in parallel batches.
8. Review every return as ACCEPT, PATCH, or RE-BRIEF.
9. Let the manager integrate shared files.
10. Run `/fstack-check` on the complete result.
11. Run `/fstack-simplify` if the result grew too much.
12. Update documentation and capture one useful lesson.
13. Run `/fstack-push` when the work is ready.

Do this manually at first.

The point is to understand where your real gates are.

Automation should come after the process works.

## The bottleneck moved

For most of my career, implementation was the bottleneck.

An idea could take weeks before I had something real enough to judge.

Now I can produce working software much faster.

The bottleneck moved to decisions:

- is this worth building?
- what is the smallest useful version?
- what must stay true?
- which work can safely run in parallel?
- is the result coherent?
- should this exist at all?

This is why I do not want the software factory to become fully automatic.

The factory should make my judgment travel further.

It should not replace judgment with volume.

## fstack is becoming an operating system for building

I still like that every fstack skill is small.

The factory did not require turning fstack into a large framework.

It required giving those small skills roles inside a larger system.

`PLAN.md` became the production order.

`AGENTS.md` became the operating manual.

A strong reasoning model became the manager. Today I use GPT-5.6 Sol, and Opus 5 is another great choice.

Composer subagents became the production cells.

`/fstack-check` became the quality gate.

`/fstack-simplify` became the station that removes excess.

The documentation and work log became the factory memory.

And I remained responsible for deciding what enters the line and what leaves it.

This is how I am building now.

Not one giant prompt.

Not an agent swarm making independent decisions.

A small, understandable production system for turning clear decisions into working software.

You can find fstack on [GitHub](https://github.com/flaviocopes/fstack). It is free, open source, and works with agents that support skills.
