Skip to content

Maintenance Factory

A useful “dark factory” is not an agent with a large prompt and unlimited authority. It is a small-work queue with explicit promotion, isolated execution, bounded retries, and production evidence.

Flow-Next supplies the lifecycle engines:

  • Pilot selects one blessed item and advances one build stage.
  • Land owns the PR after Pilot reports DEFERRED_TO_LAND.
  • Tracker Sync lets Linear, Jira, GitHub, or GitLab provide the promotion signal.
  • Worktree Kit supplies isolated checkouts.

The queue policy on this page is an orchestration pattern above those primitives, not a dark-factory command or a promise that Flow-Next understands your deployment topology. Your prompt, scheduler, and repository rules define scope, concurrency, release, and production verification.

flowchart LR
    A["Backlog item"] --> B{"Human-blessed?"}
    B -- "No" --> A
    B -- "ready=true or exact tracker state" --> C{"Workable maintenance spec?"}
    C -- "Thin or consequentially ambiguous" --> D["Park with exact question"]
    C -- "Yes" --> E["Claim + isolated worktree"]
    E --> F["Pilot: one stage per tick"]
    F --> G{"PILOT_VERDICT"}
    G -- "ADVANCED" --> F
    G -- "ASKED / NEEDS_HUMAN" --> D
    G -- "DEFERRED_TO_LAND" --> H["Land: CI, review, merge, release"]
    H --> I{"Runtime-affecting?"}
    I -- "No" --> J["Tracker reconciliation + closeout"]
    I -- "Yes" --> K["Approved deployment path + per-target verification"]
    K --> J

The important boundaries:

  1. Promotion is human-owned. A local ready=true or the exact configured tracker.readyState is the blessing. The operator may read that signal; it never promotes an unblessed item itself.
  2. Fitness is narrower than readiness. A promoted ticket can still be too thin to execute. Require a clear goal, boundaries, acceptance criteria, verification, dependencies, and no unresolved consequential ambiguity.
  3. The maintenance lane is deliberately boring. Bug fixes, regressions, bounded UI/UX improvements, docs, reliability, tests, and maintenance qualify. New product features, major architecture, broad migrations, new schemas or connectors, destructive operations, and product-policy decisions do not.
  4. Isolation is per item. Keep one registered .worktrees/<spec-branch>/ checkout for the item’s full lifecycle. Every state-changing Pilot, test, QA, PR, and Land action runs there. (Since 4.1.0 this composes fully: pilot’s plan/plan-review stages run inside a secondary worktree instead of demanding the default branch.)
  5. Readiness is not a concurrency lock. Before claiming, inspect active claims, registered worktrees, open branches and PRs, dependencies, and changed-file overlap against fresh origin/main.
  6. Production completion is project-defined. Land follows repository release instructions; your operator adds the guarded deployment and live-verification steps for every required target. Documentation-only changes do not invent a runtime rollout.

Set the tracker state once:

Terminal window
flowctl config set tracker.readyState "Ready for Dev"

Use the exact workflow-state or status name configured for the project. Linear and Jira readiness is state-based; GitHub and GitLab readiness is label-based. Tracker-connected projects treat the tracker as authoritative: pull-side reconciliation projects that signal onto the local spec’s ready flag.

Valid intake shapes:

  • Flow spec only, with ready=true.
  • Tracker issue only, in the exact promoted lane.
  • Linked tracker issue and Flow spec.

Tracker-only work is valid intake, not executable work: backlog mode parks it with a request to capture or interview a Flow spec rather than treating issue prose as an implementation contract. Planning is not a prerequisite for promotion. Pilot can plan and run plan review once a self-contained Flow spec exists. A self-contained specification is the prerequisite for execution.

When a promoted item lacks enough authority, park it with one exact question:

Should retries stop after the third failure or continue until the 30-second deadline?

Do not ask:

Can you clarify the requirements?

Backlog mode records these as durable async questions and emits PILOT_VERDICT=ASKED. The queue can continue with independent items while that one waits.

Fetch before selection and conflict assessment:

Terminal window
git fetch --prune origin
git worktree list --porcelain
flowctl list
gh pr list --state open --json number,headRefName,baseRefName,url

For the selected spec:

  1. Resolve its canonical branch name.
  2. Reuse its registered worktree if one already exists.
  3. Otherwise create .worktrees/<canonical-branch>/ from fresh origin/main.
  4. Run the whole lifecycle from that path.

Treat overlap as unsafe when concurrent work would require either agent to guess merge order, duplicate a shared contract change, or repeatedly rebase across an actively changing area. Record a machine-readable defer reason, preserve readiness, and reconsider after the conflicting branch merges.

A practical defer record needs at least:

{
"spec": "fn-42",
"kind": "overlap",
"conflicts_with": "fn-39",
"surfaces": ["src/billing/contract.ts", "api/invoices"],
"reconsider_after": "fn-39 merged to origin/main"
}

Do not turn temporary overlap into a human escalation. Do escalate a semantic merge conflict: autonomous conflict resolution is safe only when ownership and integration order are mechanically obvious.

Adapt the bracketed project details. Keep the scope and authority clauses; delete deployment language only when the repository truly has no runtime.

/goal Drain the blessed maintenance queue to production completion.
Eligible intake:
- Bug fixes, regressions, bounded UI/UX improvements, documentation,
maintenance, reliability, and test improvements.
- Exclude new product features, major architecture changes, broad migrations,
new connectors or production schemas, consequential product-policy choices,
destructive data operations, and work that materially expands a spec.
- Promote only when a Flow spec has ready=true or its tracker issue is in the
exact configured tracker.readyState. Never promote an unblessed item.
- Accept Flow-only, tracker-only, and linked items as queue intake. Park a
tracker-only item for capture/interview; never execute directly from issue prose.
Planning may happen in Pilot once a Flow spec exists.
- Before execution require a self-contained specification: clear goal,
boundaries, acceptance criteria, verification, dependencies, and no unresolved
consequential ambiguity. Park thin items with one exact human question.
Isolation and selection:
- On every wake, fetch origin before selecting work or assessing overlap.
- Before claiming, inspect active Flow claims, registered worktrees, open
branches and PRs, dependencies, and changed-file overlap against origin/main.
- Before state-changing work, create or reuse the spec's registered worktree at
.worktrees/<canonical-branch>, based on fresh origin/main.
- Run every Pilot stage, test, QA pass, PR update, and Land remediation for the
spec from that worktree. Keep it for the entire lifecycle.
- Defer materially overlapping work with a machine-readable reason. Preserve its
readiness and reconsider after the conflicting branch merges. Never guess
through semantic conflicts or modify another agent's checkout.
Execution:
1. Select one eligible independent item read-only.
2. In its worktree, invoke /flow-next:pilot --backlog --spec <spec-id>.
3. Repeat one Pilot stage at a time while it reports ADVANCED.
4. On PILOT_VERDICT=DEFERRED_TO_LAND, invoke /flow-next:land from the same
worktree.
5. Continue Pilot and Land until the item reaches a terminal outcome.
6. Keep processing other independent items while one waits on a human,
dependency, review, CI, or overlap.
Release and verification:
- Land owns bounded CI repair, review remediation, current-head gates, merge,
release, and the repository's documented closeout.
- For runtime-affecting changes, use only the project's approved operator path
and identities. Preflight the exact project and mode before cloud actions.
- Deploy the same release to [TARGETS]. Verify each target independently:
supported public URL, release/version parity, interface or schema conformance,
health, and spec-specific behavior.
- Report sparse or unavailable tenant data honestly; do not silently omit a
target or turn absence of sample data into a false failure.
- Documentation-only changes still require PR, CI, merge, and release closeout,
but no invented runtime deployment.
- Preserve tenant isolation and repository data-safety rules. Never delete,
truncate, drop, recreate, weaken authorization, expose credentials, or widen
scope without explicit human approval.
Cadence:
- During a wake, continue immediately while useful state-changing work exists.
- When all remaining work awaits CI, review, another agent, a dependency, the
Land patience window, or human input, end the cycle. Wake about once per hour.
- Do not continuously poll or repeatedly report unchanged state.
- Reconsider parked and overlap-deferred items only on an hourly wake or after a
known conflicting merge.
Stop and request human intervention only for:
- unclear or expanding scope; ineligible new-feature work;
- missing acceptance or verification authority;
- unresolved consequential UX, product, security, privacy, tenancy, schema,
migration, retention, or destructive-operation decisions;
- missing operator authorization or failed project preflight;
- semantic merge conflicts; exhausted bounded CI or review remediation;
- production verification that cannot safely roll forward or back;
- any Pilot or Land NEEDS_HUMAN verdict.
Completion:
- Stop permanently only after Pilot and Land both report NO_WORK on two
consecutive hourly wakes, unless new eligible work appears.
- Require every resulting PR merged, required release/deployment complete,
runtime changes verified on every target, and Flow/tracker state reconciled.
- Final report: each item, PR, merge/release id, tests, deployment targets,
live-verification evidence, and every parked human question.

This prompt intentionally contains more policy than command syntax. Pilot and Land already know how to advance their stages. The queue controller’s job is to decide what may enter, where it may run, when it must wait, and what counts as production proof.

/goal is convenient in an interactive host. The same policy can be run by launchd, cron, a CI scheduler, or an internal control plane that starts one fresh headless session per wake.

Store the adapted goal in a reviewed repository file such as:

.flow/automation/maintenance-queue.md

Keep the goal body intact; the runners below strip the interactive /goal prefix from its first line and replace it with a one-wake instruction. Then choose one runner. Run it from a trusted repository with Flow-Next installed and the required GitHub/tracker/cloud credentials already provisioned.

Terminal window
repo_root="/srv/acme-app"
prompt_file="$repo_root/.flow/automation/maintenance-queue.md"
run_log="$repo_root/.flow/tmp/maintenance-$(date -u +%Y%m%dT%H%M%SZ).jsonl"
factory_prompt="$( { printf '%s\n\n' "Run one maintenance-factory wake cycle."; sed '1s|^/goal ||' "$prompt_file"; } )"
cd "$repo_root" &&
claude -p "$factory_prompt" \
--output-format stream-json \
--verbose \
--permission-mode acceptEdits \
--max-budget-usd 25 \
</dev/null | tee "$run_log"
Terminal window
repo_root="/srv/acme-app"
prompt_file="$repo_root/.flow/automation/maintenance-queue.md"
run_id="$(date -u +%Y%m%dT%H%M%SZ)"
run_log="$repo_root/.flow/tmp/maintenance-$run_id.jsonl"
final_log="$repo_root/.flow/tmp/maintenance-$run_id.final.txt"
factory_prompt="$( { printf '%s\n\n' "Run one maintenance-factory wake cycle."; sed '1s|^/goal ||' "$prompt_file"; } )"
codex exec \
-C "$repo_root" \
--sandbox workspace-write \
--json \
--output-last-message "$final_log" \
"$factory_prompt" \
</dev/null | tee "$run_log"

Equivalent headless entry points — Cursor agents, Factory Droid automation, a Kubernetes job, or an internal scheduler — work if they can load the project rules and Flow-Next skills, mutate only the intended workspace, and return a durable transcript.

Prefer one fresh wake-cycle process over a shell process that sleeps forever:

  • The external scheduler owns the hourly cadence and retry policy.
  • Each run has a hard budget and an inspectable exit.
  • Credentials can be short-lived.
  • A crashed agent does not become a silent immortal poller.
  • The two-consecutive-NO_WORK counter can live in small scheduler state rather than model memory.

Do not pass secrets in the prompt or command line. Inject them through the runner’s secret store or provisioned operator identity. A headless host still needs the same repository lock, exact worktree ownership, and cloud preflight as an interactive run.

The board can be the factory’s human console:

  1. Configure tracker.readyState to an exact state such as Ready for Dev.
  2. Keep unapproved work outside that state.
  3. Move a bounded, self-contained maintenance issue into it to bless execution.
  4. Let backlog-mode Pilot union tracker-only, Flow-only, and linked items.
  5. Let async questions and lifecycle updates reconcile back to the issue.

For Jira, the promoted lane is queried using the configured status name. For Linear, the workflow-state name is matched exactly after normalization. No separate “agent ready” score should infer promotion from priority, labels, assignee, or prose.

An external scheduler may use Jira, Linear, GitHub Actions, or another queue to wake the controller, but it should not duplicate Flow-Next’s stage machine. Feed the same reviewed maintenance goal to the host, let Pilot and Land emit their verdicts, and store the transcript plus release evidence as the run receipt.

A factory that only counts merged PRs will optimize for easy PRs. Track:

  • promoted → first action latency;
  • time parked and the exact missing authority;
  • ASKED, BLOCKED, and NEEDS_HUMAN rates by cause;
  • overlap-defer time;
  • first-pass CI and review success;
  • bounded remediation exhaustion;
  • merge → release → per-target verification latency;
  • production-verification failures and rollback/roll-forward outcomes;
  • items reopened after “completion.”

The useful unit is not agent activity. It is a blessed maintenance item closed with current-head review, reproducible tests, release identity, and live proof.