Skip to main content

Loopflow

Loopflow helps you create and run Waves — persistent agents that work toward an outcome. You write a wave's goal once; it works a roadmap, delegates the implementation to workers, remembers what it learns, and shows you every live session.

Start a wave by hand and steer it interactively. As it earns trust, let it loop — picking work, dispatching flows, and reacting to changes on its own.

Waves

A wave is a named agent with a goal. Two files author it:

File Holds
wave/<name>/GOAL.md The wave's intent and loop prompt — what it's for, how it judges progress
wave/<name>/MEMORY.md What the wave remembers between loops — written by the wave agent
<!-- wave/designer/GOAL.md -->
---
primary_flow: build
metrics:
  - design reviews are complete
---

Keep the design system coherent. Each loop: read the roadmap, pick the next
design task, dispatch a worker to build it, and fold what changed into memory.

Run the wave in your terminal:

lf wave designer             # the wave's server: one persistent mind, until Ctrl-C
lf chat "ship the button audit first"     # post into its thread (any process can)
lf memory add "buttons: variants unified" # curate what it knows

Sessions are plain tmux — tmux ls to see the wave agent and its workers, tmux attach -t <name> to jump into one.

lf wave <name> starts a long-lived server at the repo's main checkout (the wave's journal and endpoint live at the origin); the resident mind — one persistent codex thread — enters the wave's worktree to work. Progress and chat are a single conversation: human messages steer a live turn by default, attributed messages (workers, scripts) queue for the next one, and interrupt finalizes a partial turn. Truth is an append-only journal, so a restart keeps the whole thread. lf chat and lf memory are the message doors for minds, workers, humans, and scripts; worker reports arrive attributed in the thread. Outside any wave a publish drops silently (exit 0) — the verbs are safe in every prompt. See rust/loopflow/src/wave/README.md for the wire contract, and scripts/demo_wave.sh for the guided demo.

The five Viable System Model charters ship as builtin goals s1s5. Run one directly:

lf wave s3           # the s3 (control) charter

The wave agent coordinates; it rarely writes code itself. When it picks a substantial task it dispatches a worker — a scoped agent that runs a flow, opens a PR, and reports back:

lf build "unify button variants" --wave designer --dispatch

Workers inherit the wave's GOAL.md and MEMORY.md, so they build with its intent in view. Their PRs are how results flow back to the wave.

Crons

Crons schedule supplementary flows on a wave — maintenance that runs independently of the worker pool. They live in GOAL.md frontmatter; the wave's resident mind fires each due schedule as a system turn. workers: 0 is valid for a cron-only wave.

<!-- wave/governance/GOAL.md -->
---
primary_flow: garden
workers: 0
crons:
  - flow: govern-identity
    schedule: "0 0 0 * * Sun *"
---

GitHub webhooks

lfd verifies each GitHub webhook and translates it inward as an lf exec. For the current demo path, CI failures and main pushes arrive as attributed chat notifications; the architecture direction is durable facts plus explicit commands for long-term coordination.

Event What lfd runs
CI fails on a wave's PR lf chat --wave <name> "CI failed: …" — the mind decides how to fix (usually a ci-fix worker)
PR merged lf op queue reconcile --wave <name>
Push to main lf chat --wave <name> "main moved: …" — the mind decides whether to rebase or integrate

Steps

lf debug -c    # paste an error, watch it fix
lf op pm show --wave designer   # print the wave's live Asana roadmap
lf design      # interactive design session
lf gstack/office-hours   # run a built-in gstack workstyle step
lf office-hours          # same thing — bare name works when unambiguous
lf npx/vercel-labs/deep-research   # fetch any Claude Skill live and run it
lf op sync-skills       # write steps into .claude/skills and .agents/skills

Steps are prompts that run coding agents. Add your own in .lf/steps/.

lf op sync-skills mirrors resolved steps into vendor Skill directories so compact skill invocations work in Claude and Codex sessions (/step for Claude, $step for Codex handoffs). It writes repo-local skills by default; add --global --yes to write generated skills under ~/.claude/skills and ~/.agents/skills.

Names resolve in this order: your repo (.lf/steps/<name>.md, .lf/steps/<ns>/<name>.md, or .claude/commands/<name>.md) → your global dir (~/.lf/steps/<name>.md, ~/.lf/steps/<ns>/<name>.md, or ~/.claude/commands/<name>.md) → core builtins (build/, govern/, ops/) → namespaced builtins (gstack/, …) → external skill namespaces. A bare name resolves to a namespaced builtin only when exactly one namespace has that name. Namespaced steps and flows use /, not :. For third-party skills, use lf npx/<owner>/<repo> (or lf npx/<name> once cached or searchable via npx skills). The legacy rams/rams shim also resolves when ~/.claude/commands/rams.md exists.

Steps and flows are organized into three categories by agency: build (manual work you drive), govern (autonomous coordination the system drives), ops (side-channel utilities).

Build steps (build/)

Manual work — you invoke these, often interactively.

Step What it does
kickoff Elaborate design — alternatives, research, imagine success/failure
research Map the territory — architecture, complexity, quality, potential
iterate Read research, write design to address it
refresh-plan Reconcile scratch/ with the branch after rebasing
reduce Find simplification opportunities
polish Find polish priorities
expand Find expansion opportunities
5whys Root cause analysis on a bug fix
implement Build from a design doc
compress Simplify touched code
gate Ship-ready code and reviewer-friendly docs
debug Fix an error
ci-fix Fix failing CI checks for the current PR
integrate-upstream Adapt wave code after rebasing onto main
qa Thorough quality assessment of the current branch
triage Assess QA findings, separate blocking from polish
design Interactive design session
explore Investigate the codebase
demo Experience-first walkthrough of observable changes
code-review Walk through structural and architectural decisions
review-design Reshape AI-elaborated design into user intent
refine Refine existing work
review-open-work Survey branches, PRs, worktrees, and waves for inbox-zero triage

Govern steps (govern/)

Autonomous coordination — crons and waves-watching-waves drive these.

Step What it does
scan Read member wave state — PRs, blocks, progress, git activity
assess Judge wave health and identify pressure points
wave-report Read health signals across all waves
mutate Compose and apply coordinated mutations across member waves
review Review mutations, amend or revert if needed
s5-scan Scan wave identity, children, policy, and recent structural change
s5-assess Assess identity, boundary, roster, and autonomy drift
s4-scan Scan dependencies, advisories, upstream APIs, and other external signals
s4-assess Assess which environmental changes matter and what they imply
s3-scan Scan live health, velocity, CI, retries, and usage signals
s3-assess Assess control health, mechanical blocks, and worker-pool size
s2-scan Scan backlogs, PR overlap, path overlap, and conflict history
s2-assess Assess coordination risk, conflict map, and safe ordering

Ops steps (ops/)

Side-channel utilities — wrappers around git, PR, release, and wave state.

Step What it does
init Set up loopflow in this repo
commit Commit with generated message
rebase Rebase onto main
pr Generate PR title/body and call lf op pr --title --body
land Land PR, rotate worktree
lint Run linter, fix issues
update-wave Create, update, or delete wave state
split-wave Split a wave into smaller independent waves
release Run the full release workflow (notes, PR, tag, status)
release-notes Write narrative RELEASE_NOTES.md from release context, preferring release decisions when present
synthesize Combine multiple perspectives into one
token-compress Compress text into a target token budget without silently dropping important information
validate Validate flows, steps, and directions

Flows

lf design && lf implement && lf gate    # chain steps manually
lf build                                # or use a named flow

Steps chain into flows. Flows feed into waves.

Flows can include mechanical ops items directly:

- implement
- gate
- op: land --create-pr

Build flows (build/)

Flow Steps
build kickoff → review-design → loop(code → xor(demo, code-review), exit: gate) → deploy
build-or-silent xor(build, silence)
design-and-ship design → implement → reduce → polish → deploy
queue compress → update-wave → gate
code implement → compress → lint → gate
pair design → code
deploy gate → op: land --create-pr
ship refresh-plan → implement → gate → op: pr → op: land
incident debug → 5whys → code → deploy

Govern flows (govern/)

Flow Steps
garden scan → assess → xor(garden-act, silence)
garden-act mutate → review
govern-operations xor(s1-build, silence)
govern-coordination s2-scan → s2-assess → mutate
govern-control s3-scan → s3-assess → mutate
govern-intelligence s4-scan → s4-assess → mutate
govern-identity s5-scan → s5-assess → mutate
s1-build kickoff → code → deploy

Ops flows (ops/)

Flow Steps
release op: release run patch
sync rebase → integrate-upstream

deploy lands the branch. sync rebases the current branch and refreshes the default branch. That default-branch refresh is safe from sibling worktrees: it stashes any dirty edits on the checked-out default branch, syncs, then restores them — but only when those edits don't touch paths the sync itself rewrote. If they collide (e.g. the branch just absorbed a merge over the same files), the edits stay in a sync_main: auto-stash stash instead of being merged back, so a sync can never silently revert just-landed work.

Release artifacts

cat release/unreleased/DECISIONS.md
lf op release run patch
find release -maxdepth 2 -type f | sort
Path What it does
release/unreleased/DECISIONS.md Append-only ledger of release-worthy intent and policy decisions during the current cycle
release/vX.Y.Z/DECISIONS.md Archived decision ledger for a shipped version
release/vX.Y.Z/NOTES.md Snapshot of the release notes generated for that shipped version
RELEASE_NOTES.md Always-latest release notes at the repo root

Interactive runs append to release/unreleased/DECISIONS.md when they make a durable product or process decision. Headless runs do not. If the ledger exists, lf op release run promotes release/unreleased/ to release/v<version>/, uses DECISIONS.md to shape the narrative release notes, and archives the generated root notes to release/v<version>/NOTES.md. If the ledger is absent, release notes fall back to merged PR history.

Browse the catalog

lfd serve
curl -s "http://127.0.0.1:2486/v0/catalog?repo=$(pwd)" | jq '.result.flows[] | {name, category, source}'

Open Flows in Concerto to browse the same catalog visually. The left pane groups flows and steps by build, govern, and ops; the right pane shows every parent flow that uses the selected flow or step.

Branches (xor)

Branches route a flow based on an agent's assessment of the current state. Exactly one path runs.

# flow: garden
- scan
- assess
- xor:
    router: assess
    paths:
      act:
        flow: garden-act
        description: "Adjustments needed  mutate waves, then review"
      silence:
        description: "Everything is healthy"

The xor construct runs a router step that reads scratch/ and chooses a path. The router's prompt gets routing instructions appended automatically — the step author focuses on what to think about, not how to express the choice. A path with no flow: or step: (like silence) is a clean no-op exit.

If no router: is specified, a generic routing agent picks a path based on scratch/ contents.

Playing in the Waves

Once you're chaining steps into flows, you're ready to ride a wave. Write its wave/<name>/GOAL.md, then run the agent:

lf wave engbot             # start the wave agent

Directions compose extra nuance into any step or flow the wave dispatches.

lf research -d ux,clarity
lf research -d ceo

Install

curl -fsSL https://github.com/loopflowstudio/loopflow/releases/latest/download/install.sh | sh

Or grab the desktop app: download Loopflow-latest.dmg and drag Loopflow to Applications. The app bundles lf and lfd.

Default install location is ~/.local/bin. Override with LF_INSTALL_DIR=/path.

install.sh only downloads the lf and lfd binaries. To connect Claude, GitHub, and optional providers, run lfd install—add --no-interactive to skip the prompts (CI, Docker, scripted installs).

From a dev checkout, build everything locally with one entry:

uv run python scripts/install.py local --use   # full build: lf, lfd, Loopflow.app -> local-bin/, make active
uv run python scripts/install.py refresh       # CLI refresh: pull default branch, rebuild/install lf+lfd, sync skills

install.py is the local entry point. local --use builds this worktree's lf, lfd, and Loopflow.app into <worktree>/local-bin/, then promotes that build. refresh is the fast CLI-only path: pull the default branch, rebuild lf/lfd, install them into the local bin dir, and sync loopflow steps into ~/.claude/skills and ~/.agents/skills. Both paths run lf op sync-skills --global --yes after installing, so Claude and Codex always see the latest steps.

Built-in steps and flows included. lf init sets up your coding agent and preferences.

cargo install --git https://github.com/loopflowstudio/loopflow --bin lf --bin lfd

Install the Rust binaries directly with cargo.

Dispatch and Observe

lf wave engbot       # start the wave agent (Ctrl-C to stop)
lf implement "Add the endpoint" --wave engbot --dispatch
tmux ls              # list live sessions — the wave agent and its workers
tmux attach -t <name>  # attach to one

Read wave/engbot/GOAL.md and wave/engbot/MEMORY.md for a wave's state, or watch it in Concerto. To remove a wave, delete wave/engbot/ and its worktree (lf op wt remove engbot).

lf op auth status    # provider auth status (GitHub / Claude / Codex / OpenCode Zen / Asana)
lf op auth github    # connect GitHub in your browser
lf op auth claude    # connect Claude in your browser
lf op auth codex     # connect Codex in your browser
lf op auth zen       # connect OpenCode Zen in your browser
lf op auth asana     # connect Asana with OAuth
lf op auth disconnect github

The roadmap lives in Asana. Pin a wave to its Asana project in wave/<name>/GOAL.md frontmatter — lf op pm init writes this for you:

# wave/designer/GOAL.md frontmatter
pm:
  asana_project: 1207xxxxxxxxxxxx
lf op branches list --user @me --stale 60d   # preview stale remote branches
lf op branches prune --user @me --stale 60d  # delete after confirmation
lf op pm init --wave designer                # connect/create the Asana project, write asana_project into GOAL.md
lf op pm show --wave designer                # print the wave's live Asana roadmap
lf op pm update --wave designer --title "Add dark mode" --notes "..."   # create a task
lf op pm update --wave designer --id 1207... --title "..." --status done # update or close a task
lf op pm status                              # show linked waves

lf op pm reads and edits the roadmap directly in Asana — there is no local mirror and nothing to sync. Task notes preserve basic markdown formatting: Loopflow writes rich text through html_notes and falls back to plaintext notes when a task has none yet.

The loopflow Python package is a library only (wire models). Use the install script or cargo to install lf and lfd.

Documentation →

tmux Plugin

# Add to .tmux.conf
set -g @plugin 'loopflowstudio/loopflow.tmux'
run '~/.tmux/plugins/tpm/tpm'

Status bar shows wave state: [lf: main] or [lf: 3 waves | engbot]. Customize the format:

# .tmux.conf
set -g @loopflow_status_format '⚡#{status}'       # change wrapper
set -g @loopflow_status_format '[#{branch}]'        # branch only
set -g @loopflow_status_format '[lf: #{status}]'    # default

Variables: #{status} (computed text), #{branch}, #{step}, #{waves}, #{wave}.

Keybindings start with prefix+l:

Key Action
r Run step/wave
s Stop
o Open logs
p Open PR
n Next iteration
d Land PR
u Start/bootstrap
w Pick wave/worktree
L Pick layout
? Help

Two built-in layouts: lf-dev (editor + agent + shell), lf-swarm (monitor + 3 worktree workers).

Works without lf installed — status shows placeholder, keybindings display clear messages.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

loopflow-0.10.0.tar.gz (14.3 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

loopflow-0.10.0-py3-none-any.whl (15.4 kB view details)

Uploaded Python 3

File details

Details for the file loopflow-0.10.0.tar.gz.

File metadata

  • Download URL: loopflow-0.10.0.tar.gz
  • Upload date:
  • Size: 14.3 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for loopflow-0.10.0.tar.gz
Algorithm Hash digest
SHA256 2d910e4e3d7b75997dded727e8c7f5659ae6eabff3417588baf8ff37b70183cc
MD5 6f54e25270b6b3806163da9ba03f48db
BLAKE2b-256 5f6e18313b5b5fac6b118faa93c83cb56ccd4a7cd0006cc9710b35fa90bc778c

See more details on using hashes here.

Provenance

The following attestation bundles were made for loopflow-0.10.0.tar.gz:

Publisher: release.yml on loopflowstudio/loopflow

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file loopflow-0.10.0-py3-none-any.whl.

File metadata

  • Download URL: loopflow-0.10.0-py3-none-any.whl
  • Upload date:
  • Size: 15.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for loopflow-0.10.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d00c57f10204889f9676ff8dc1858a96ebbc37133f4de5aa7f6fb829ec145ede
MD5 6023efc8801f31bfe7857cf7e1d40df0
BLAKE2b-256 30eb30fd89281f0525eaf90b025e6e5068d3c2203f93077dd41d2da2fcfa1ff2

See more details on using hashes here.

Provenance

The following attestation bundles were made for loopflow-0.10.0-py3-none-any.whl:

Publisher: release.yml on loopflowstudio/loopflow

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.10.1

2 files

This release

0.10.0 This release

2 files

0.9.12

2 files

0.9.11

2 files

0.9.10

2 files

0.9.9

2 files

0.9.7

2 files

0.9.6

2 files

0.9.2

2 files

0.9.0

2 files

0.8.6

2 files

0.8.5

2 files

0.8.4

2 files

0.8.3

2 files

0.8.2

2 files

0.8.1

2 files

0.8.0

8 files

0.7.2

2 files

0.7.0

2 files

0.6.11

2 files

0.6.6

2 files

0.6.5

2 files

0.6.4

2 files

0.6.3

2 files

0.6.2

2 files

0.6.1

2 files

0.6.0

2 files

0.5.2

2 files

0.5.1

2 files

0.5.0

2 files

0.4.0

2 files

0.3.0

2 files

0.2.2

2 files

0.2.1

2 files

0.2.0

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page