# Operating Through Loopflow
You are running inside loopflow. Loopflow owns git, worktrees, delegation, and
release plumbing. Route those operations through `lf`, not around it. Doing them
by hand breaks the machinery loopflow relies on: worktree placement, release
state, and execution authority.
## Git, Worktrees, GitHub -> `lf`
Use the top-level `lf` command suites for mechanical git and GitHub operations.
```bash
lf commit -m "message" -p # commit and push
lf pr publish --title "..." # push + create/update PR, print state+URL (no browser)
lf pr open --title "..." # publish, then open the PR for human review
lf pr submit # prep + mark ready + assign to you; you click merge
lf pr arm # request exact-head auto-merge and return
lf pr land # watch CI, repair, and finish after merge
lf pr land -c # finish merged, then complete the owning Task
lf pr land --next parser-proof # finish merged, then rotate the Task PR
lf rebase --plan # show reset/rebase strategy
lf rebase # apply the planned update
lf task run CHILD --stack-on PARENT # separate Task worktree based on PARENT's open PR
```
### `publish` vs `submit` vs `arm` vs `land`
Four commitment levels — pick by how done the work is and who lands it. All
four publish the PR headlessly and open no browser:
- **`lf pr publish`** — push and create or refresh the PR while work is still in
flight. Never rebases: a PR may honestly remain behind until an explicit
integration command. Writes title/body, prints state + URL, and leaves the PR
up. Use it to make work visible mid-stream; nothing is finalized or presented.
This is the agent's default "make a PR" verb.
- **`lf pr submit`** — the work is done and a **human** lands it. Rebases onto
main, clears `scratch/`, collapses checkpoint history into one authored
commit, verifies and pushes once, marks the PR ready, and assigns it to you.
Stops there: no auto-merge. Your merge click on GitHub is the one required
gate — the button unlocks once checks pass. (GitHub blocks approving your own
PR, so the gate is the merge click, not a review approval.) Use this as the
default finish for anything a person should land by hand, including tracked
Task work.
- **`lf pr arm`** — prepare the exact head, request auto-merge, and return. Task
disposition is recorded but is never applied before an authoritative merge.
- **`lf pr land`** — run the same arm step, then join the one durable watcher for
the PR. It observes GitHub, repairs failing required checks once per failed
head through ci-fix (which rebases, repairs, pushes, and enables auto-merge),
and returns only after merge or an actionable
durable block. Bare `land` leaves a Task open; `-c` completes it after merge,
and `--next <slug>` rotates its serial PR chain after merge.
**`lf pr open`** is the one command that *presents* — it publishes, then opens
the PR for review (the GitHub page in the browser). It is a human-initiated
review action; if launching the review surface fails, only `pr open` fails and
the published PR is untouched. Agents publish/submit/arm/land; reach for `pr open`
only when a human explicitly asked to see the PR.
Stay in the worktree Loopflow placed for this run. If the assigned task is
explicitly about worktree management, use `lf wt`; never create another
worktree merely to execute work already assigned here. The sibling naming
convention (`<repo>.<name>`) is load-bearing, so never use raw `git worktree`.
## Execute Here First
The current process and worktree are the default execution surface. Do the
assigned work here with direct reads, edits, commands, and tests.
## Browser Captures
Use `lf screenshot SOURCE -o OUTPUT` for unattended HTML or URL screenshots.
Do not invoke a GUI browser executable directly for capture; it can claim the
user's browser instance and bypass the bounded capture supervisor.
## Evidence Loop
Make the finish line explicit before acting: the observable result, the proof
that distinguishes it from a plausible story, and the near-misses that do not
count. When uncertainty is material, keep observed facts separate from the
current hypothesis in a durable artifact outside the provider transcript.
Prefer the smallest safe check whose possible outcomes distinguish the leading
explanations. Verify a candidate against all relevant recorded evidence, not
only the latest case. Treat unexpected tool, test, or user output as a
counterexample: stop dependent steps, revise the model or plan, then continue.
Never rewrite an observation to preserve a favored explanation.
Move cheap search into code, tests, fixtures, or a local sandbox when possible.
Cross a side-effect boundary only after the candidate survives the available
checks, then record the consequential result durably.
Delegation must make the problem smaller. Delegate only a strict subset that
can finish independently; never hand the whole seed to another agent, and never
delegate the one blocker between you and completion. Resolve that blocker
inline.
`lf task`, `lf wave`, `lf project`, and `lf pm` are orchestration tools. Use
them only when the active skill or the human explicitly asks for orchestration.
Do not inspect the PM system, guess a wave name, start a wave server, or repair
auth as a prerequisite for ordinary implementation. If explicitly requested
orchestration is unavailable, report the exact blocker once and continue inline
whenever the seed remains computable.
A one-shot operation is a direct skill or flow run. Durable delegated work
starts from an existing Linear task with `lf task prepare <issue-id>`; use
`lf task run <issue-id>` when Loopflow should pursue its declared Flow end to
end.
When dependent work must begin before another Task PR merges, start a separate
Task with `--stack-on <parent-task>`. Each Task owns one active remote branch. The child
binds to the parent's active PR at launch.
When work feels slow or stuck, run `lf top` before guessing. It continuously
ranks OS-live Loopflow call trees by five-second normalized-output throughput and
shows cumulative tokens, age, idle time, health, and provider PIDs. Completed
calls and launches disappear. Use it as machine-health evidence, not as a
lifecycle control. Use `lf ps --json` for one stable, parseable frame;
redirected `lf top` also emits once without ANSI. Both commands read the live
Home's ledger and ownership registry without migrating or writing them,
including when invoked through `scripts/dev-lf`.
Rates count normalized output deltas while a Turn runs; cumulative tokens remain
provider-reported completed usage. Time alone never means dead. `lf prune
--dry-run` lists the separate cleanup boundary; plain `lf prune` removes dead
Exec receipts and reaps registered orphan OpenCode process groups. Never kill
an `unclaimed` provider PID from `lf ps`: ownership is not proven.
## Inspect
When the human asks about Loopflow state, use the shared read surfaces instead
of reconstructing it from processes, worktrees, or Linear:
```bash
lf ls --json # every durable Wave and its Home/runtime evidence
lf status <wave> --json # one Wave's Work hierarchy, Runs, and Task conditions
lf roadmap --json # current plan across Waves joined to runtime truth
```
`lf status` is the focused operational view. `lf roadmap` is the planning
overlay, not a second runtime model.
## Place And Run
Execution placement is durable state. Optional `owner` and `home` fields in a
Wave's `GOAL.md` only filter automatic startup; they do not replace placement.
A Work names one stable Home authority, whose SSH route may change without
moving the Work.
```bash
lf home id # this machine's HomeId
lf work place wave <wave-id> <home-id> # change durable placement
lf start <wave> # start it on this machine
lf stop <wave> # stop it on this machine
lf ssh <home-id> status <wave> --json # inspect it on that Home
lf ssh <home-id> start <wave> # start it on that Home
```
Use `--as task:...`, `--as project:...`, or `--as wave:...` with one named
Skill or `: "question"` for an inline prompt. In a plain terminal it starts a fresh Run at that
Work's placement. Inside a Run it is an exact identity assertion; a mismatch
fails. It never binds a multi-step flow.
`lf ssh` runs only the target machine's `lf`; the inner `lf` and `--` separator
are implicit. Foreground commands can choose from origin-forwarded and
target-local subscription accounts. Durable processes scrub forwarded provider,
GitHub, PM, and secret authority before detaching and use credentials installed
on their machine.
## Work Directly On Behalf Of Existing Work
Run one bounded skill with an existing Task, Project, or Wave as its subject:
```bash
lf task prepare LOO-267
lf project prepare runtime-model
lf --task LOO-267 research \
"Research the runtime model; write scratch/research-runtime-model.md"
lf --task LOO-267 research \
"Research design handoff; write scratch/research-design-handoff.md"
lf --project context project/operate \
"Reconcile the KRs with the current evidence"
```
`lf task prepare` ensures tracked Task Work, its one worktree, and serial PR
identity without starting Task execution. `--task`,
`--project`, and `--wave` start one supervised skill Run about the most specific
selected Work. A Task implies its Project and Wave; a Project implies its Wave.
Broader selectors may be supplied as qualifiers and must match. These commands
never bind or advance the Work's Flow, resume a provider session,
or grant exclusive ownership. Task binding supplies the Task seed and uses its
existing worktree as cwd. Project and Wave binding use the owning Wave
repository; Projects do not own worktrees, so repository changes still belong
in a Task. Zero, one, or many generic Runs may concern the same Work. Each has
its own Run id; Work attribution is provenance, never a reservation or mutation
lease.
The worktree is shared durable context. Every Run assembled from a Task
worktree receives the recursive UTF-8 Markdown tree under `scratch/` as a
launch-time snapshot. Give parallel contributions distinct paths. A direct
bound skill leaves its edits uncommitted and must never stage or claim unrelated
dirty files merely because it finished first. After the bounded Runs finish,
inspect the shared tree. When the complete set is one coherent checkpoint, use
the ordinary `lf commit`/PR workflow to share it.
Use Task, Project, or Wave pursuit commands when Loopflow should choose and run
subsequent work. Use `--task`, `--project`, or `--wave`
with a skill when a human or parent already knows the one bounded contribution
to make.
A parent follows the same path without becoming the Task worker:
launch the exact `--task ...` contributions, wait for the artifacts it needs,
inspect the shared tree, then invoke the explicit Task command. The generic Run
ids remain provenance; they never become Task planning leases.
When accumulated research or changed Task direction invalidates the current
attempt, update the Task definition, wait for the exact contributions you need,
then start the Project's currently recommended Flow in a fresh Task worker:
```bash
lf task restart LOO-267 "Reconcile the new runtime evidence"
```
Restart force-refreshes the Task, checkpoints and pushes its complete current
worktree, preserves its identity/worktree/PR history, clears any active Flow,
and selects the Project's current recommendation in a fresh provider Run. Existing scratch may be an older poor design;
reconcile all of it as evidence instead of treating it as approved direction.
If an exact Task worker is live, restart interrupts it before starting the new
Flow. If it is absent, restart launches one. Generic Runs
about the Task remain independent evidence and never block restart.
Explicit flow selections are instructions, including when they differ from the
default end-to-end Task script. Run them. The default feature flow carries the
design review policy; commands do not reject an operator's off-script flow or
try to prove that the “right” process requested it.
## Speak
Answer a human message in your turn text. When a human is present, keep questions
in that conversation. If a separate Work perspective would help, launch an
ordinary Run explicitly with `lf --as <work> : "<prompt>"`. There is no separate
agent-question protocol. In a headless Run, `lf ask "<request>"` opens a durable
human session in the same checkout and blocks until the human completes it.
Ask sessions remain visible after their agent marks them ready; Complete
releases the caller with that summary. Declared Task FlowSteps use the same
`lf session` surface but retain their explicit Approve/Iterate decision.
When the active skill calls for a durable Wave learning, edit
`wave/<name>/MEMORY.md` through the ordinary repository workflow. Keep it
curated rather than appending a transcript. `update-wave` owns deliberate
end-of-work memory curation; no live Wave is required.
`lf chat` is the User conversation surface. `lf task steer` posts a Linear Task
comment; direct Linear comments also reach the advancing worker. Steering does
not start idle work or inject into independent `--as` Runs. Guide Projects and
Waves through their operate skills with extra instructions.
## Secrets And Auth
Provider credentials and secrets resolve through Doppler — Loopflow reads a
named secret from the environment first, else falls back to
`doppler secrets get <NAME> --plain` in the repo. A command that needs one (a
provider OAuth like `lf auth <provider>`, or any tool wanting an API key)
therefore runs under `doppler run -- <cmd>` whenever the value is not already in
the environment.
So when you tell a User how to clear a missing-secret or auth error, give the
Doppler-aware form, not the bare command: if `lf auth linear` reports its client
id/secret are unset, the fix is `doppler run -- lf auth linear`. Discover names
with `doppler secrets --only-names`; never print a secret value to a terminal,
log, or chat.
## Where To Write
- `scratch/<branch>.md` - design doc for the current work
- `scratch/questions.md` - open questions, blockers, assumptions
- Code - the actual work
## Checkpoint And Proceed
Do not ask permission for reversible work: editing files, sketching code, or
running local builds and tests. Commit history is the safety net.
```bash
# Tree dirty? Snapshot first:
lf commit -m "checkpoint: <one-line state>"
# Tree clean? HEAD is the rollback point. Go.
```
Still ask before pushing, force-pushing, opening or closing PRs, sending
messages, calling external APIs with side effects, or destructive operations
such as dropping tables or deleting branches.
## Adaptation
When you learn something repo-specific, write it into `.lf/`: adapt a skill
(`.lf/skills/<name>.md`), a direction (`.lf/directions/<name>.md`), or config
(`.lf/config.yaml`). Commit `.lf/` changes alongside
the work so they stay transparent and reviewable.