How I turned fstack into a software factory
By Flavio Copes
How I use fstack, Fable, bounded subagents, repository context, and review gates to build many software products without losing control.
I recently launched 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.
The projects are very different. I have small static sites, sites with hundreds of generated pages, applications with accounts and payments, and 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, by which I mean a repeatable production system. Work enters in one form, passes through clear stations, gets inspected, and leaves in a better-defined form.
This is not a magic machine that turns one sentence into a startup. Every agent has a bounded job, and I check every result.
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 should be a working, verified, documented change that still matches the original product decision.
The full line looks like this:
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, answer product questions, approve the plan, and decide whether the result is good.
The factory removes repeated implementation work, but I still make the judgments.
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.
You might get an agent changing the data model, another inventing a design system, and two editing the same shared file. Another adds a library, while the last 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, and repository files made the state durable.
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:
fstack-nail -> fstack-plan -> fstack-build -> fstack-check -> fstack-push
The other skills support the line:
/fstack-roastchallenges the idea before I invest in it/fstack-interviewrecords the product context/fstack-simplifyremoves unnecessary complexity/fstack-designbrings the interface back to the existing design system/fstack-counselorsasks three independent models about a difficult decision/fstack-documentwrites and updates the project documentation/fstack-learnsaves 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. I can inspect what happened before sending the work to the next station.
The factory starts before code
A fast factory can manufacture the wrong thing very efficiently, so 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
I use it 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:
## 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:
### 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.
Fable is the factory manager
I currently use Fable 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:
Use Fable 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 Fable with another strong reasoning model and keep the same system.
The model names will change again, but I will keep these roles. One agent owns the plan, and worker agents do 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. It makes the decisions, writes the briefs, and rejects 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 resolves the important questions before delegating execution.
Every worker gets a real brief
A vague prompt creates vague work.
Every production cell receives a self-contained brief with five parts:
## 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.
I end every brief with:
Flag uncertainty; do not guess silently.
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:
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 help, but the manager still reads the actual files, checks the diff, and walks through the brief line by line.
Every return gets one of three verdicts:
- ACCEPT means the work matches the brief
- PATCH means the work has a trivial issue the manager can fix immediately
- RE-BRIEF means 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 proves it by running the checks that fit the product. That might mean tests, a site build, 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 reports the problem without fixing it automatically, keeping review and repair as separate jobs.
Simplification is its own station
/fstack-simplify only removes and reduces. It leaves working designs and frameworks alone.
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, and context windows fill. A new agent tomorrow will not remember the decision made tonight.
The repository must carry the important state.
I use a few plain files:
AGENTS.mdcontains product context, architecture rules, and learned preferencesPLAN.mdcontains the current production order and its boundariesdocs/overview.mdexplains the product in plain languagedocs/architecture.mdexplains how the parts fit togetherdocs/reference.mdrecords files, configuration, commands, and environment needsLEARNED.mdstores 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:
## 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.
The repository explains the product, while the work log shows 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 gives me a known production line, not a rule that every product must look identical.
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 removes accidental choices while leaving room for 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.
I started with the data schema and validation rules, then ran the research route by route. I integrated the visible section only after the reports passed source-type, duplicate, attribution, depth, and date checks.
In another, I planned framework editions for 18 working software packages.
Before any port began, each software package 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. Instead of a vague instruction to “make 18 apps,” I followed these steps:
- define what must remain true
- establish one known baseline
- divide the products by complexity
- give each cell a bounded edition
- inspect every result against the same contract
- publish only the editions that pass
The same system also works for smaller products.
A site with four pages does not need eight workers. Each delegation needs a brief, a worker run, and a review. 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.
They include a content library, a business application, a course, a browser tool, a visual product, and a software package with source code.
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.
A worker does not get to change the product direction after finding an interesting feature in the code. Public names, pricing, positioning, and shared data contracts also stay with the manager unless a brief says otherwise.
A confident summary is not enough reason to merge, and a passing build does not make unfinished work ready to deploy. When a worker is uncertain, I want the uncertainty reported rather than turned into guessed code.
I also choose the fstack skills for the task instead of running all of them automatically.
I might need a plan but not a roast. A clear task does not need /fstack-nail, and 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 creates seven agents looking for something to do.
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, but the manager selects one 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, so /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:
npx skills@latest add flaviocopes/fstack
Then add a short coordination section to the repository’s AGENTS.md:
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:
- Run
/fstack-roastif the idea needs honest pressure. - Run
/fstack-interviewto record product context. - Run
/fstack-nailif the first task is unclear. - Run
/fstack-planand approvePLAN.md. - Let the manager map dependencies and file ownership.
- Write one complete brief per worker task.
- Run independent tasks in parallel batches.
- Review every return as ACCEPT, PATCH, or RE-BRIEF.
- Let the manager integrate shared files.
- Run
/fstack-checkon the complete result. - Run
/fstack-simplifyif the result grew too much. - Update documentation and capture one useful lesson.
- Run
/fstack-pushwhen the work is ready.
Do it manually at first so you understand where the real gates are. Automate it 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?
I do not want the software factory to become fully automatic. I want it to extend my judgment, not replace it with more output.
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.
In this system, PLAN.md is the production order and AGENTS.md is the operating manual. A strong reasoning model manages the work. Today I use Fable, and Opus 5 is another great choice.
Composer subagents are the production cells. /fstack-check provides the quality gate, while /fstack-simplify removes excess. The documentation and work log hold the factory memory.
I still decide what enters the line and what leaves it.
This is how I am building now: a small production system that turns clear decisions into working software. I can understand each part and keep independent product decisions away from an agent swarm.
You can find fstack on GitHub. It is free, open source, and works with agents that support skills.
Want me to talk about your product? You can sponsor this site.
Related posts about ai: