# Unattended operation

Source: https://flow-next.dev/autonomy/unattended-operation/

The queue policy above the loops - bounded intake, worktree isolation, overlap control, hourly wakes, tracker integration, release proof, and headless runners.

A queue that runs while nobody watches 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:

* [`flow --auto`](https://flow-next.dev/autonomy/pilot/) selects one blessed item and drives it hop after hop to its terminal (`--tick` advances one stage per invocation).

* [Land](https://flow-next.dev/autonomy/land/) takes one named pull request to merge, and merges only with consent given in the session. There are two ways to give it:

  * **One command per item:** `/flow-next:flow --auto <spec-id> --until=merge`. The flag is the merge consent. Flow builds, opens the pull request, invokes land on it as its last stage, and waits out CI and review for that one item.
  * **Two stages:** without the flag, a run from intent ends with `ADVANCED` once make-pr has opened the pull request, and a later run that finds the open pull request stops at `DEFERRED_TO_LAND`. Either way your controller names that spec’s pull request and authorizes its merge. Use this when the queue should keep building other items while one pull request waits. The controller prompt below is written this way.

* [Tracker Sync](https://flow-next.dev/integrations/tracker-sync/) lets Linear, Jira, GitHub, or GitLab provide the promotion signal.

* [Worktree Kit](https://flow-next.dev/skills/worktree-kit/) supplies isolated checkouts.

The queue policy on this page is an **orchestration pattern above those primitives**. Flow-Next ships no queue command and knows nothing about your deployment topology. Your prompt, scheduler, and repository rules define scope, concurrency, release, and production verification.

## The operating model

```mermaid
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["flow --auto: one item to its terminal"]
    F --> G{"PILOT_VERDICT"}
    G -- "ADVANCED, --tick run, build stages left" --> F
    G -- "ADVANCED with make-pr" --> P["PR handover"]
    G -- "ASKED / NEEDS_HUMAN" --> D
    G -- "DEFERRED_TO_LAND" --> H["Land the named PR: threads, CI, merge"]
    P --> H
    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 `flow --auto`, test, QA, PR, and Land action runs there. The `plan`/`plan-review` stages run inside a secondary worktree instead of demanding the default branch, so this composes fully.
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 stops at the confirmed merge. Your operator runs the repository’s release instructions and adds the guarded deployment and live-verification steps for every required target. Documentation-only changes do not invent a runtime rollout.

## Promotion and parking

Set the tracker state once:

```bash
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 refine a Flow spec rather than treating issue prose as an implementation contract. Planning is not a prerequisite for promotion. Once a self-contained Flow spec exists, `flow --auto` builds it directly, planning only when a plan signal is present. 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.

## Isolation and overlap

Fetch before selection and conflict assessment:

```bash
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:

```json
{
  "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.

Do not run several `flow --auto` or Land controllers in the same checkout. If several queue workers share one repository, add a scheduler-level repository lock and a per-spec claim before dispatch. Worktrees isolate files and Git indexes; they do not make overlapping product decisions safe.

## Copy-paste goal

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

```text
/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/refine; never execute directly from issue prose.
  Planning may happen in flow --auto 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 flow --auto 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:flow --auto --backlog <spec-id>. One
   invocation drives the item to its terminal verdict; add --tick to advance one
   stage per wake instead, and repeat it while it reports ADVANCED.
3. Read the terminal PILOT_VERDICT line.
4. On PILOT_VERDICT=DEFERRED_TO_LAND, or ADVANCED with make-pr among its
   stages, find that spec's open pull request and land it: invoke /flow-next:land <PR>. I authorize merging the pull requests of
   items this controller built, once Land's gates pass.
5. Invoke Land on the same pull request again on each wake while it reports
   AWAITING_REVIEW, RESOLVING or FIXING_CI. Stop on MERGED, BLOCKED,
   NEEDS_HUMAN or NO_WORK. Never substitute another pull request.
6. Keep processing other independent items while one waits on a human,
   dependency, review, CI, or overlap.


Release and verification:
- Land owns review-thread resolution, one CI fix or one flake rerun per failure,
  current-head gates, and the merge of the pull request it was given. After
  LAND_VERDICT=MERGED, run the repository's documented release and closeout
  yourself.
- 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 flow --auto or Land NEEDS_HUMAN verdict.


A human call that blocks nothing else does not stop the item: the run finishes the rest of the work and opens the pull request as a draft with the question as an open item. Under `--until=merge`, a reversible, evidence-backed call inside the spec is made and recorded in the Decisions list instead; anything else stops `NEEDS_HUMAN` before the merge, and land does not mark the draft ready on the run's authority.


Completion:
- Stop permanently only after flow --auto reports NO_WORK on two consecutive
  hourly wakes and every pull request this controller opened is merged or
  reported, 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. `flow --auto` 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**.

## Headless hourly controller

`/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:

```text
.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.

### Claude Code

```bash
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"
```

### Codex

```bash
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.

## Jira or Linear as the front door

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 `flow --auto` 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.

The board only shows `Done` once something runs the post-merge tracker step. Land does it for merges it makes. If your factory merges any other way (a merge queue, auto-merge, a person pressing Merge), add the small CI job in [Merged outside land](https://flow-next.dev/integrations/tracker-operations/#merged-outside-land), or finished work sits at `In Review` and the next promotion decision reads a stale board.

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 `flow --auto` and Land emit their verdicts, and store the transcript plus release evidence as the run receipt.

## What to measure

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 unit that matters is a **blessed maintenance item closed with current-head review, reproducible tests, release identity, and live proof**, not agent activity.
