This release is a pre-release and may not be stable for production use.
A tiny, pluggable software factory. You describe what you need, a workflow does the work, and every step an AI agent takes is fenced in by deterministic checks, budgets and a human-reviewable result.
- Declarative workflows: YAML made of plugin steps, validated before anything runs.
- Agents on a leash: the LLM is a step, never the boss. Its output is untrusted, bounded by budgets and followed by real gates (a compiler, a test run, a diff-size limit).
- Everything environment-specific sits behind ports (git host, LLM, secrets, job source, executor), so swapping GitHub for another host or Bedrock for another model is a one-line change.
- Ask in plain language:
minifactory ask "..."picks the right workflow, drafts its input, and asks before it runs.
Status: alpha. The engine, the CLI and three example workflows work and are tested; see Limitations for what has and has not been verified.
┌──────────────── core (src/minifactory/core) ────────────────┐
│ engine · workflow validation · registry · events · expr │ knows nothing about
└───────────────────────────┬─────────────────────────────┘ languages, git hosts or LLMs
ports: scm · llm · secrets · source · executor · router · intake
│
┌───────────── plugins (src/minifactory/plugins/builtin) ─────┐
│ github · local-git · bedrock · openai · jev router │
│ shell.run · agent.edit · flutter.* · scm.open_pr · ... │
└─────────────────────────────────────────────────────────┘
The rule that keeps it from becoming spaghetti: the core never imports a plugin; plugins register themselves.
Install
Pre-release.
0.0.2a1is an alpha:pipanduvskip pre-releases unless you ask, so a plain install still gets0.0.1. To try the alpha:uv tool install --prerelease allow minifactoryorpip install --pre minifactory.
The easiest way to get the minifactory command is a tool installer, which keeps it isolated and on your PATH:
uv tool install minifactory # or: pipx install minifactory
uv tool install "minifactory[aws]" # + boto3, for the Amazon Bedrock LLM
Or with plain pip, ideally inside a virtual environment:
pip install minifactory
pip install "minifactory[aws]"
minifactory: command not foundafterpip install? pip puts console scripts next to the Python it installed into, and that folder is often not on yourPATH(typical with the python.org macOS installer, where it is/Library/Frameworks/Python.framework/Versions/3.X/bin). Useuv tool install/pipx, add that folder toPATH, or runpython3 -m minifactory .... Beware of zsh'sAUTO_CD: if a folder calledminifactoryexists where you are, typing the bare word changes into it instead of reporting the missing command.
From source, for development:
git clone https://github.com/juan-campuzano/minifactory && cd minifactory
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev,aws]"
Python 3.11+. Workflows live in a workspace, not in the package (see below).
Quick start (offline, no keys, no SDK)
minifactory init my-factory && cd my-factory # a workspace: minifactory.yaml + workflows/
minifactory workflows list # templates that ship with the package
minifactory workflows copy flutter-app-factory # copies the workflow and its sample inputs
minifactory validate flutter-app-factory # fail-fast checks, runs nothing
minifactory run flutter-app-factory # runs 4 sample jobs with canned LLM replies
This example factory turns an app spec into a project: plan, implement, build/test gates, an automatic repair
loop, a non-blocking coverage check, then delivery. The offline run uses a simulated flutter and canned LLM
replies, so what it produces is not a real project. It exists to show every path the engine can take:
| sample job | what it exercises |
|---|---|
todo_app |
happy path |
counter_needs_repair |
the first attempt breaks the build; the repair loop fixes it |
notes_low_coverage |
coverage below the threshold never blocks delivery, it annotates it |
bad_spec |
the plan is not valid JSON, so the job fails early and nothing is built |
Each job leaves state.json, result.json and its working copy in .minifactory/runs/<workflow>/<job>/;
events.jsonl records every step and LLM call (tokens and cost when the provider reports them).
minifactory run ... --resume restarts from the first step that did not finish ok.
Workspaces
Code ships in the package; your content lives in a workspace, found like git (nearest minifactory.yaml going up from
the current directory, else ~/.config/minifactory):
my-factory/
minifactory.yaml optional settings: runs_dir, output_dir, router, threshold, plugins
workflows/ your workflows, the ones `minifactory ask` can choose from
... anything your workflows reference (specs/, fixtures/...), relative to this folder
Relative paths inside a workflow resolve from the workspace root, wherever you run minifactory inside it.
Command-line flags override minifactory.yaml, which overrides the defaults.
Example workflows (templates)
Copy one into your workspace with minifactory workflows copy NAME; only copied workflows are routable by ask.
| template | what it does | needs |
|---|---|---|
flutter-app-factory |
the offline demo above | nothing |
app-factory |
creates a new project (an app, a CLI, a library) from a one-line request, in Python, Node, Java or Flutter, sized to the request | AWS credentials (Bedrock) and the stack's tools |
fix-bug |
fixes a bug in an existing GitHub repo (Python, Node or Flutter, detected from its files): reproduces it with a failing test, fixes it minimally, opens a PR | gh auth login, AWS credentials, the stack's tools |
create-workflow |
drafts a new workflow from a plain-language goal, using only the steps and plugins that exist (see below) | AWS credentials (Bedrock) |
java-migration-demo |
a batch transform over toy repos: deterministic branch vs LLM branch, baseline gate, repair loop | nothing |
Describe what you need: minifactory ask
export TYPESAFE_API_KEY=... # for the default router (Jev); `--router keyword` works offline
minifactory ask "a simple app to track my expenses" --dry-run # picks a workflow, drafts its input, runs nothing
minifactory ask "a simple app to track my expenses" # same, then asks before running
- A router plugin chooses among the workflows that declare a
route:block, and says how confident it is. - Policy lives in code, not in the model: with
--yesit only acts when the router is confident, the request is actionable and a workflow fits; otherwise it exits without doing anything. - The workflow's intake plugin drafts its input from your text (the text is treated as data, the result is validated), and you confirm before anything runs.
- Where results go is your choice for new projects:
--output local(a plain git folder) or--output github(a new private repo plus a pull request;--publicto change that).
Languages: stack profiles
Everything language-specific is data: a stack profile says how to recognise a stack, how to scaffold it, which commands
analyse and test it, where code and tests live, and what an LLM should know about its idioms. Packaged: python, node,
java (JDK only: no Maven, Gradle or JUnit) and flutter. ask picks the stack from your request, and when it matches
none of them it says so instead of building the wrong thing:
$ minifactory ask "a cobol program that prints hello"
error: no supported stack matches this request (got 'unsupported'; available: flutter, java, node, python). Add one as stacks/<name>.yaml
Add a language by dropping a YAML file in your workspace's stacks/ folder (field reference in docs/stacks.md):
no code needed.
Fix a bug in an existing repo
minifactory workflows copy fix-bug
minifactory ask "the counter goes up by 2 instead of 1 in acme/todo_app" --dry-run
fix-bug clones the repo with gh, requires the repo to analyse cleanly, selects the relevant files, writes a test
that reproduces the bug (and stops without changing anything if that test does not fail), fixes it with an
exact-match patch, re-runs the checks, enforces a size limit on the change, and opens a pull request.
It never touches the default branch.
Let the factory write workflows
minifactory workflows copy create-workflow
minifactory ask "create a workflow that clones a GitHub repo, runs dart format and opens a pull request"
minifactory workflows list # the result is listed under "drafts"
minifactory workflows enable dart-format-pr # shows what it would do, asks, then activates it
The agent reads a catalog generated from the plugins installed right now (minifactory plugins --schema prints the same
text), writes draft.yaml, and must pass the same validator as any workflow; errors go back to it through the usual repair
loop. If the goal needs something that does not exist it declines with MISSING: <what> instead of inventing a step.
The result is only ever a draft: it is not routable by ask and never runs until you enable it, and enable first lists
every shell command, repository write and paid LLM call it contains.
Design principles
- Untrusted agent output. Edits are parsed strictly: a
PATCHmust match exactly once or nothing is written; paths cannot escape the repo; plans are validated with pydantic; the Bedrock provider rejects a reply cut off by the token limit. - Bounded loops. Repair attempts, unproductive attempts, features per plan and context size all have budgets.
- Deterministic gates after every agent step.
on_fail: discardstops a job without changing anything;blocking: falselets enrichment steps annotate a result without stopping it. - Generated workflows are drafts. A person reviews and enables them; nothing an LLM wrote runs on its own.
- Proposals, not pushes. Changes to existing repos arrive as a pull request on a new branch.
- No silent fakes. The simulated
flutteris opt-in (tool: fakeorFACTORY_FLUTTER=fake); by default the real SDK is required and a missing one is an error.
The workflow format
Deliberately small: sequence, when, on_fail: fail|discard|continue, blocking: false, and ${...} templating
over job, steps, vars and env. No loops, no calls, no arithmetic: if you need that, write a step in Python.
Everything checkable is checked at load time: unknown plugins, typos in parameters, missing providers, bad when
syntax, references to steps that run later.
Write a plugin
No core changes needed. A step is a class with typed parameters:
# my_plugin.py
from minifactory.core.context import Step, StrictParams
from minifactory.core.models import StepResult
from minifactory.core.registry import register
class Params(StrictParams): # unknown keys in the YAML are errors
message: str
@register("step", "demo.hello")
class Hello(Step):
Params = Params
def run(self, ctx, p):
return StepResult.ok(f"hello {ctx.job.name}: {p.message}")
minifactory run my-workflow --plugin my_plugin
Installed packages can instead expose the minifactory.plugins entry point and are discovered automatically.
Plugin kinds: step, source, executor, scm, llm, secrets, router, intake. Built in:
| kind | built in |
|---|---|
scm |
github (via the gh CLI), local-git, local-dir |
llm |
bedrock, openai (any OpenAI-compatible endpoint), fixture, scripted |
router |
jev (TypeSafe), keyword |
intake |
app-spec, repo-task |
source |
app-specs, repo-tasks, catalog, static |
executor |
local, threads |
secrets |
env |
See docs/plugins.md for each kind's interface, and AGENTS.md if you are an AI
coding agent (or work with one) on this repo.
Limitations
- Alpha. Only Python 3.11 and 3.13 are tested in CI.
- Stack profiles ship for Python, Node, Java (JDK only) and Flutter. A Maven/Gradle project needs your own profile.
- The gates check that generated code is consistent (it builds and its own tests pass), not that it does what you meant: a generated Java "first twenty primes" program printed the primes up to a limit, and passed its own tests.
- The real-model runs were small: a one-line app, and a seeded one-line bug in a small repo. Larger apps, where features must agree with each other, are not solved: expect failures there.
- The
githubprovider has been exercised against a fakeghin tests and has created repos in manual runs; the existing-repo flow has only been run against a local git remote, not against a real GitHub repository. - No built-in retry or timeout policy at the engine level, and no persistent state store beyond local JSON files.
Development
pip install -e ".[dev]"
ruff check src tests examples
pytest -q # no network, credentials or Flutter SDK needed
License
MIT, see LICENSE.
Metadata
Release files for minifactory 0.0.2a1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| minifactory-0.0.2a1.tar.gz | 99.1 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| minifactory-0.0.2a1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 191.2 kB
Release files / minifactory-0.0.2a1.tar.gz
| Download URL | minifactory-0.0.2a1.tar.gz |
|---|---|
| Size | 99.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
84905a52d3624e3b834a33684a5ef2a12754b651fa01a3091ec88aeb0d0791fe
|
|
BLAKE2b-256 checksum How to use checksums |
c80fd4963cb0cee2a2029e768f7c24d16865177dc7100ddd58f3e580508e959c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.
Transparency logRelease files / minifactory-0.0.2a1-py3-none-any.whl
| Download URL | minifactory-0.0.2a1-py3-none-any.whl |
|---|---|
| Size | 92.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
76b9067c913394be3596f77fb1c9a68dbdc0efbfc7b26f856ce47ceac85bd51a
|
|
BLAKE2b-256 checksum How to use checksums |
a4bcd0202581b87b027dc7de1906ccafcaf8d913e0b7901e77087f3c66e21ecc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.
Transparency logSecurity for minifactory 0.0.2a1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for minifactory-0.0.2a1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.