A software factory you run from a phone
The software-factory plugin: a request becomes work a person approves from one card, a contract a headless worker executes in its own checkout, evidence QA checks against the contract, and a release the asker hears about. Three pages, four seats, gates at every handoff. vocion-core#655, #658, #672, #683, #695.
Status: shipped. The software-factory plugin ships in vocion-core at
packages/core/templates/plugins/software-factory/. Its 2.0 rebuild is
vocion-core#655 and
#658 (merged 2026-09-24); the gates it
declares are #672 and
#683 (2026-09-24); triage naming the platform
piece is #695 (2026-09-25). Live on the instance
that runs Vocion for Metacto since the 2026-09-25 pin bump to 3179fafa. Turn it on with:
# workspace.yaml
plugins: [software-factory]
What it is
A request — a bug, a store review, a support email, an incident, an ask typed into chat — becomes
one request record in the asker's words. A product manager prepares the commitment: a draft
contract, the main risk, the expected result, how it will be checked, and a mockup when the change
is something people will see. Then the product owner decides from one card: Approve build,
Request changes, or Defer with a reason and a revisit date. Approving freezes the acceptance
criteria. Nothing executes on a draft.
The contract — an engineering_task with an objective, the base commit, the paths the worker may
touch, the checks that must pass, the acceptance criteria, a risk class — goes to an engineer that
runs as an external worker in its own checkout. It pushes a factory/ branch, opens a pull
request, attaches the proof. QA reads the contract, the diff and the evidence — never the
engineer's conversation — and writes a verdict bound to the commit it read. The engineering
owner merges from a card carrying the commit, the verdict, the risk class and the rollback; the
card says STALE when the branch has moved. Whatever deployed writes the release; the PM tells the
asker on their channel; and after a check window the request gets a result: helped, did not
help, or not enough evidence.
That is the loop: asked → decided → planned → building → QA → released, with an answered branch for the things that will not be built and the asker told why.
Three pages
The first version of this plugin had nine pages. On 2026-09-24 the brief was: "I only want to see 3 pages. Products, Work, Releases. The work object should encompass the full loop. I should be able to run a whole software company from my phone." Every page and every element was kept only if a product exec can make a decision or get value from it.
| Page | The question it answers |
|---|---|
| Products | How are my products doing? Stage, health, price beside the incumbent, last release, open work — one derived sentence per product. |
| Work | What is running, what is proposed, what just landed — and what is waiting on me? Three tabs; a row is one outcome. |
| Releases | What reached people, what it carried, what the post-deploy check said, who has been told? |
Opening a row on Work opens the work item: the ask, the decision and who made it, the plan, the mockup, the contract, every run with its checks and cost, the pull request, QA's verdict, the release, the after-shot. Every stage that did not happen says so. The page is hidden from the nav because it is the row, not a place.
Factory, Factory log, Performance and Guide are gone. They explained the machine, and the machine can be complicated; the product cannot be. Reporting comes back when use demands it.
Four seats
| Seat | Agent | Owns | Never |
|---|---|---|---|
| PM | product-manager (lead) | triage, in scope or not, the plan, the contract, telling the asker | merges, writes code |
| Design | designer | the mockup before a decision, the after-shot before a close | builds, decides |
| Eng | task-engineer (runsOn: external-worker) | the change inside allowedPaths, the checks with artifacts, the PR | merges, deploys, touches a credential |
| QA | change-reviewer | the verdict against the contract and the evidence | merges, sees the engineer's conversation |
Each seat has a one-page rubric — the question it is judged by — as a skill in the plugin (#665). Three standing missions: no request waits more than a week, every asker hears back, every criterion is proven or named unproven. Ten automations wake them — a request arrives, a decision lands, the weekday planning pass, a failed check on a factory branch, work finished, and QA's three red-team reads (the proposal at triage, the diff at PR open, the evidence when checks pass).
Gates at the handoffs
The seats' instructions alone would drift. Same day as the rebuild: a PM card that invented an iOS harness for a web app; a contract dispatched without reading the repo; a bug report that filed the wrong request. So the plugin declares handoff gates on its object types:
decision-readyonrequest.state → in_scope: product named, a reason from the closed list, at least three acceptance criteria a person can check, an expected result, how we check, a decision cost. Then the PM's own rubric judges the card, calibrated on the reference cases; a schema, billing, auth or infra risk always goes to a person.contract-completeonengineering_task.status → ready | dispatched: objective, base commit, allowed paths, required checks, acceptance contract, risk class.
A write that fails is refused, the record reads Returned to PM with each missing thing named, and nobody is interrupted. The mechanism is core; the plugin only says which fields, on which transition, judged by whose rubric. Quality control at the handoffs, without over-engineering is the full account.
From a phone
The decision card has a minimum — outcome, who asked, recommendation, change, done when, spend range and review minutes, main risk, expected result — so a person can decide it on a phone without opening anything else. "What should I do right now" is answered from the records with links. And since #693 the phone shell acts like an app: no zoom, no sideways scroll, a wide table scrolls inside its own box, the composer sits above the home indicator.
Two people, two decisions: the product owner commits, the engineering owner merges. A routine completion reply can go out under a policy the product owner turns on; a decline or an incident update is a person's every time.
What core had to grow
The plugin is YAML and markdown. What it needed from core, each landed generic: the
engineering_task storage and the worker_run control plane (claim, lease, heartbeat,
checkpoint, budget); the external-worker harness target; the handoff
gate grammar on object types; a plugin's own nav section
(nav: {section: Software factory}) and offered routes — the factory lists Evals under its
"More ›" so the reference sets sit one tap from the pages they grade
(#692). Triage now also names the platform
piece a request touches and, while planning, adds a candidate for core when the shape would serve
another workspace (#695) — the ladder, concrete → abstract → core, run by the factory on itself.
What is not there
Performance and reporting pages, per-run activity logs, board counters, the incumbent price check, dependency currency, the nightly e2e mission, tag audits, batches of ten. Each was built; each was removed on 2026-09-24 because it explained the machine rather than helping a person decide. The first live judged gate crossing has not yet been observed on the box; the deterministic half has. The typed card contract that would let the plugin add its own card kinds — the gate verdict, the QA finding, the release — is specified and not built.
The workspace fixtures in the plugin are fictional. Metacto is the seller in every fixture; no customer, repository or product of a customer appears in it.