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 · expressions │
└──────────────────────────────────────────────────────────────────┘
knows nothing about languages, git hosts or LLMs; those sit behind ports:
scm · llm · secrets · source · executor · router · intake
┌─ plugins (src/minifactory/plugins/builtin) ──────────────────────┐
│ steps/ shell · agent · stack · flutter · scm · workflows │
│ providers/ github · local-git · bedrock · openai · secrets │
│ routing/ jev and keyword routers · intakes │
└──────────────────────────────────────────────────────────────────┘
The rule that keeps it from becoming spaghetti: the core never imports a plugin; plugins register themselves.
Install
Pre-release.
0.0.2a3is 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).
Tab completion
minifactory completion install # shows what it will change and asks first
minifactory completion status # installed / stale / missing
minifactory completion uninstall # puts your rc file back exactly as it was
It cannot happen by itself at install time (neither pip nor uv runs anything), so it is one command. install detects your shell
(zsh, bash or fish; --shell to choose), writes the script under ~/.config/minifactory/completion/ and adds a small marked block
to your rc file (~/.zshrc, ~/.bashrc or ~/.bash_profile; fish needs no edit). It keeps a one-time backup, is safe to run twice, and
--dry-run prints everything without touching anything. minifactory doctor tells you if it is missing or out of date after an upgrade, and
minifactory init mentions it once in a terminal.
Tab completes commands and flags, and the names that exist in your workspace: your workflows (minifactory run <Tab>), the packaged
templates (workflows copy <Tab>), drafts waiting to be enabled (workflows enable <Tab>) and the routers (ask --router <Tab>). Start
typing a path (./, workflows/) and it completes .yaml files instead. It needs the minifactory command on your PATH (see Install).
Prefer to wire it yourself? eval "$(minifactory completion show zsh)" (or bash; for fish minifactory completion show fish | source).
Use eval "$(...)", not source <(...): macOS's bash 3.2 cannot source a process substitution. fish is generated by argcomplete but I have
not tested it.
Check your setup: minifactory doctor
minifactory doctor # what is installed and configured: toolchains per stack, AWS, gh, router key
minifactory doctor fix-bug # what THIS workflow needs: a missing requirement fails (exit code 1)
minifactory doctor --online # also contacts AWS and GitHub to check the logins work
minifactory doctor --json # for scripts and CI
A missing toolchain is only information until a workflow needs it. Secrets are reported as "set", never printed, and
nothing leaves your machine unless you pass --online.
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.
Skills: reusable guidance for agent steps
A skill is a SKILL.md (YAML frontmatter with name and description, then markdown) that tells an agent how you want
something done. Add skills from a path or a GitHub URL; a folder or repository with many skills adds them all:
minifactory skills add ./my-skills
minifactory skills add https://github.com/owner/repo # every SKILL.md in the repo
minifactory skills add https://github.com/owner/repo/tree/main/skills # ...or under one folder
minifactory skills list
add shows each skill (name, description, size) and asks before copying it to skills/ in your workspace (--global for
all workspaces). Then a step opts in: agent.edit, agent.plan_app, agent.implement_spec and agent.repair_build take
skills: [tdd, review]. Only the text is used: scripts next to a SKILL.md are not copied and nothing is executed.
A skill goes into a prompt, so read third-party ones first.
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
-
Commands see no credentials by default. The generated code and the tests of a repository you clone run with a filtered environment (no AWS keys, tokens or API keys;
pass_envadds names on purpose). Files are not hidden: a sandboxed runner is next. -
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.2a3
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.2a3.tar.gz | 99.1 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| minifactory-0.0.2a3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 222.4 kB
Release files / minifactory-0.0.2a3.tar.gz
| Download URL | minifactory-0.0.2a3.tar.gz |
|---|---|
| Size | 99.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b08c23bb4444c05ab8c4f3ea156ec52246821d829ccf196b38b029d952d5a5ab
|
|
BLAKE2b-256 checksum How to use checksums |
9e474d82edfe8b5baf32e318a6b2a6fd43e7e0cb296c18858e67b4b4677bad97
|
| 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.2a3-py3-none-any.whl
| Download URL | minifactory-0.0.2a3-py3-none-any.whl |
|---|---|
| Size | 123.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
673c5736fda43264d8d468fdc6972d68fe4bc72712a691a4bb71ef2a3a0f174f
|
|
BLAKE2b-256 checksum How to use checksums |
2a926127f04d15deeecd3e4816bc4d7f5f37abb8c0c5206cd7cb6a6010c2589f
|
| 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.2a3
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.2a3.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.