loopflow 0.5.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. loopflow-0.5.2/.gitignore +11 -0
  2. loopflow-0.5.2/PKG-INFO +203 -0
  3. loopflow-0.5.2/README.md +174 -0
  4. loopflow-0.5.2/pyproject.toml +61 -0
  5. loopflow-0.5.2/src/loopflow/__init__.py +1 -0
  6. loopflow-0.5.2/src/loopflow/builtins/__init__.py +15 -0
  7. loopflow-0.5.2/src/loopflow/builtins/commit_message.txt +26 -0
  8. loopflow-0.5.2/src/loopflow/builtins/pr_message.txt +48 -0
  9. loopflow-0.5.2/src/loopflow/cli/__init__.py +97 -0
  10. loopflow-0.5.2/src/loopflow/cli/agent.py +447 -0
  11. loopflow-0.5.2/src/loopflow/cli/commit.py +82 -0
  12. loopflow-0.5.2/src/loopflow/cli/compare.py +199 -0
  13. loopflow-0.5.2/src/loopflow/cli/land.py +215 -0
  14. loopflow-0.5.2/src/loopflow/cli/maestro.py +75 -0
  15. loopflow-0.5.2/src/loopflow/cli/meta.py +475 -0
  16. loopflow-0.5.2/src/loopflow/cli/ops.py +26 -0
  17. loopflow-0.5.2/src/loopflow/cli/pr.py +334 -0
  18. loopflow-0.5.2/src/loopflow/cli/run.py +533 -0
  19. loopflow-0.5.2/src/loopflow/cli/sessions.py +88 -0
  20. loopflow-0.5.2/src/loopflow/cli/status.py +49 -0
  21. loopflow-0.5.2/src/loopflow/config.py +131 -0
  22. loopflow-0.5.2/src/loopflow/context.py +283 -0
  23. loopflow-0.5.2/src/loopflow/design.py +48 -0
  24. loopflow-0.5.2/src/loopflow/files.py +242 -0
  25. loopflow-0.5.2/src/loopflow/frontmatter.py +216 -0
  26. loopflow-0.5.2/src/loopflow/git.py +202 -0
  27. loopflow-0.5.2/src/loopflow/init_check.py +40 -0
  28. loopflow-0.5.2/src/loopflow/launcher.py +596 -0
  29. loopflow-0.5.2/src/loopflow/llm_http.py +203 -0
  30. loopflow-0.5.2/src/loopflow/logging.py +71 -0
  31. loopflow-0.5.2/src/loopflow/maestro/__init__.py +45 -0
  32. loopflow-0.5.2/src/loopflow/maestro/agent.py +154 -0
  33. loopflow-0.5.2/src/loopflow/maestro/agent_runner.py +55 -0
  34. loopflow-0.5.2/src/loopflow/maestro/agents.py +199 -0
  35. loopflow-0.5.2/src/loopflow/maestro/api.py +231 -0
  36. loopflow-0.5.2/src/loopflow/maestro/collector.py +337 -0
  37. loopflow-0.5.2/src/loopflow/maestro/daemon.py +219 -0
  38. loopflow-0.5.2/src/loopflow/maestro/db.py +357 -0
  39. loopflow-0.5.2/src/loopflow/maestro/launchd.py +140 -0
  40. loopflow-0.5.2/src/loopflow/maestro/markdown.py +185 -0
  41. loopflow-0.5.2/src/loopflow/maestro/runner.py +501 -0
  42. loopflow-0.5.2/src/loopflow/maestro/session.py +56 -0
  43. loopflow-0.5.2/src/loopflow/maestro/triggers.py +91 -0
  44. loopflow-0.5.2/src/loopflow/maestro/worktree.py +96 -0
  45. loopflow-0.5.2/src/loopflow/pipeline.py +145 -0
  46. loopflow-0.5.2/src/loopflow/prompts/CHECKPOINT_MESSAGE.md +29 -0
  47. loopflow-0.5.2/src/loopflow/prompts/COMMIT_MESSAGE.md +24 -0
  48. loopflow-0.5.2/src/loopflow/publish.py +189 -0
  49. loopflow-0.5.2/src/loopflow/templates/PROMPTS.md +83 -0
  50. loopflow-0.5.2/src/loopflow/templates/STYLE.md +130 -0
  51. loopflow-0.5.2/src/loopflow/templates/commands/debug.md +42 -0
  52. loopflow-0.5.2/src/loopflow/templates/commands/design.md +58 -0
  53. loopflow-0.5.2/src/loopflow/templates/commands/implement.md +37 -0
  54. loopflow-0.5.2/src/loopflow/templates/commands/iterate.md +37 -0
  55. loopflow-0.5.2/src/loopflow/templates/commands/polish.md +48 -0
  56. loopflow-0.5.2/src/loopflow/templates/commands/review.md +69 -0
  57. loopflow-0.5.2/src/loopflow/templates/config.yaml +49 -0
  58. loopflow-0.5.2/src/loopflow/tokens.py +215 -0
  59. loopflow-0.5.2/src/loopflow/worktrees.py +167 -0
@@ -0,0 +1,11 @@
1
+ # Python
2
+ __pycache__/
3
+ .pytest_cache/
4
+
5
+ # Swift
6
+ .build/
7
+ xcuserdata/
8
+ .swiftpm/xcode/
9
+
10
+ # Claude Code (personal state)
11
+ .claude/settings.local.json
@@ -0,0 +1,203 @@
1
+ Metadata-Version: 2.4
2
+ Name: loopflow
3
+ Version: 0.5.2
4
+ Summary: Arrange LLMs to code in harmony
5
+ Author: Jack
6
+ License-Expression: MIT
7
+ Keywords: ai,claude,cli,coding,llm
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Environment :: Console
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Software Development
17
+ Requires-Python: >=3.10
18
+ Requires-Dist: fastapi>=0.115.0
19
+ Requires-Dist: pathspec>=0.11.0
20
+ Requires-Dist: pydantic-ai-slim[anthropic]>=1.0.0
21
+ Requires-Dist: pydantic>=2.12.5
22
+ Requires-Dist: pyyaml>=6.0
23
+ Requires-Dist: tiktoken>=0.7.0
24
+ Requires-Dist: typer>=0.9.0
25
+ Requires-Dist: uvicorn>=0.30.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
28
+ Description-Content-Type: text/markdown
29
+
30
+ # Loopflow
31
+
32
+ ## Usage
33
+
34
+ ```bash
35
+ lf review
36
+ lf implement: add auth
37
+ lf ship
38
+ ```
39
+
40
+ Run LLM coding tasks from reusable prompt files.
41
+
42
+ macOS only. Supports Claude Code, OpenAI Codex, and Google Gemini CLI via configuration.
43
+
44
+ ## Install
45
+
46
+ ```bash
47
+ pip install loopflow
48
+ lf ops install # installs Claude Code, Codex, Gemini CLI, worktrunk
49
+ ```
50
+
51
+ ## Why Worktrees?
52
+
53
+ Loopflow is designed for running background agents while you work on something else. That means isolated branches - you can't have an agent committing to the branch you're actively editing.
54
+
55
+ The workflow: create a worktree, run tasks there, merge when ready. You can have multiple features in flight at once.
56
+
57
+ ## Quick Start
58
+
59
+ ```bash
60
+ wt switch --create my-feature --execute pwd
61
+ cd ../loopflow.my-feature
62
+
63
+ lf design # interactive: figure out what to build
64
+ lf ship # batch: implement, review, test, commit, open PR
65
+ ```
66
+
67
+ `lf design` runs `.lf/design.lf`. `lf ship` runs the `ship` pipeline from `.lf/config.yaml`.
68
+
69
+ ## Tasks
70
+
71
+ Tasks are prompt files in `.lf/`. Here's an example:
72
+
73
+ ```markdown
74
+ # .lf/review.lf
75
+
76
+ Review the diff on the current branch against `main` and fix any issues found.
77
+
78
+ The deliverable is the fixes themselves, not a written review.
79
+
80
+ ## What to look for
81
+
82
+ - Style guide violations (read STYLE.md)
83
+ - Bugs, logic errors, edge cases
84
+ - Unnecessary complexity
85
+ - Missing tests
86
+ ```
87
+
88
+ Run tasks by name:
89
+
90
+ ```bash
91
+ lf review # run .lf/review.lf
92
+ lf review -x src/utils.py # add context files
93
+ lf : "fix the typo" # inline prompt, no task file
94
+ ```
95
+
96
+ All `.md` files at repo root (README, STYLE, etc.) are included as context automatically.
97
+
98
+ ## Pipelines
99
+
100
+ Chain tasks in `.lf/config.yaml`:
101
+
102
+ ```yaml
103
+ pipelines:
104
+ ship:
105
+ tasks: [implement, review, test, commit]
106
+ pr: true # open PR when done
107
+ ```
108
+
109
+ ```bash
110
+ lf ship # runs each task, auto-commits between steps
111
+ ```
112
+
113
+ ## Worktrees
114
+
115
+ Loopflow delegates worktree management to worktrunk. Use `wt` directly:
116
+
117
+ ```bash
118
+ wt list # show all worktrees
119
+ wt switch --create auth # create or switch to a worktree
120
+ wt remove auth # remove worktree + branch
121
+ ```
122
+
123
+ ## Session Tracking
124
+
125
+ Track running tasks across multiple terminals (maestro is optional):
126
+
127
+ ```bash
128
+ lf ops maestro start # optional web UI (tails logs)
129
+ lf ops status # show running sessions (reads SQLite)
130
+
131
+ # In another terminal
132
+ lf implement # auto mode task registers automatically
133
+
134
+ # Check from anywhere
135
+ lf ops status # see all running sessions
136
+ ```
137
+
138
+ Sessions write to SQLite in auto mode; the maestro UI reads the same database.
139
+
140
+ ## Configuration
141
+
142
+ ```yaml
143
+ # .lf/config.yaml
144
+ agent_model: claude:opus # Model: claude, codex, gemini (or backend:variant)
145
+ push: true # auto-push after commits
146
+ pr: false # open PR after pipelines
147
+
148
+ # Tasks that default to interactive mode (default is auto)
149
+ interactive:
150
+ - design
151
+ - iterate
152
+
153
+ ide:
154
+ warp: true
155
+ cursor: true
156
+ ```
157
+
158
+ ## Run Modes
159
+
160
+ By default, tasks run in **auto mode**: non-interactive with streaming output. This is ideal for most coding tasks and background execution. All runs append logs under `~/.lf/logs/<worktree>/`.
161
+
162
+ Use `-i` to run interactively (full chat, can interrupt) or configure per-task defaults:
163
+
164
+ ```bash
165
+ lf implement # auto mode (default)
166
+ lf design # interactive (from config)
167
+ lf implement -i # force interactive
168
+ lf design -a # force auto
169
+ lf implement & # background (shell handles it)
170
+ ```
171
+
172
+ ## Options
173
+
174
+ | Option | Description |
175
+ |--------|-------------|
176
+ | `-i, --interactive` | Run in interactive mode (override default) |
177
+ | `-a, --auto` | Run in auto mode (override default) |
178
+ | `-x, --context` | Add context files |
179
+ | `-w, --worktree` | Create worktree and run task there |
180
+ | `-c, --copy` | Copy prompt to clipboard, show token breakdown |
181
+ | `-v, --paste` | Include clipboard content in prompt |
182
+ | `-m, --model` | Choose model (backend or backend:variant) |
183
+ | `--parallel` | Run with multiple models in parallel |
184
+
185
+ ## Commands
186
+
187
+ | Command | Description |
188
+ |---------|-------------|
189
+ | `lf <task>` | Run a task from `.lf/` |
190
+ | `lf <pipeline>` | Run a pipeline |
191
+ | `lf : "prompt"` | Inline prompt |
192
+ | `lf ops compare a b` | Compare two worktree implementations |
193
+ | `wt <subcommand>` | Worktree management (worktrunk) |
194
+ | `lf ops pr create` | Open GitHub PR |
195
+ | `lf ops pr land [-a]` | Squash-merge to main |
196
+ | `lf ops land [--no-pr] [--force] [--base]` | Land locally via worktrunk |
197
+ | `lf ops commit [-p]` | Generate commit message and commit |
198
+ | `lf ops init` | Initialize repo with prompts and config |
199
+ | `lf ops install` | Install Claude Code, Codex, Gemini CLI |
200
+ | `lf ops doctor` | Check dependencies |
201
+ | `lf ops maestro start` | Start session tracking daemon |
202
+ | `lf ops maestro stop` | Stop session tracking daemon |
203
+ | `lf ops status` | Show running sessions |
@@ -0,0 +1,174 @@
1
+ # Loopflow
2
+
3
+ ## Usage
4
+
5
+ ```bash
6
+ lf review
7
+ lf implement: add auth
8
+ lf ship
9
+ ```
10
+
11
+ Run LLM coding tasks from reusable prompt files.
12
+
13
+ macOS only. Supports Claude Code, OpenAI Codex, and Google Gemini CLI via configuration.
14
+
15
+ ## Install
16
+
17
+ ```bash
18
+ pip install loopflow
19
+ lf ops install # installs Claude Code, Codex, Gemini CLI, worktrunk
20
+ ```
21
+
22
+ ## Why Worktrees?
23
+
24
+ Loopflow is designed for running background agents while you work on something else. That means isolated branches - you can't have an agent committing to the branch you're actively editing.
25
+
26
+ The workflow: create a worktree, run tasks there, merge when ready. You can have multiple features in flight at once.
27
+
28
+ ## Quick Start
29
+
30
+ ```bash
31
+ wt switch --create my-feature --execute pwd
32
+ cd ../loopflow.my-feature
33
+
34
+ lf design # interactive: figure out what to build
35
+ lf ship # batch: implement, review, test, commit, open PR
36
+ ```
37
+
38
+ `lf design` runs `.lf/design.lf`. `lf ship` runs the `ship` pipeline from `.lf/config.yaml`.
39
+
40
+ ## Tasks
41
+
42
+ Tasks are prompt files in `.lf/`. Here's an example:
43
+
44
+ ```markdown
45
+ # .lf/review.lf
46
+
47
+ Review the diff on the current branch against `main` and fix any issues found.
48
+
49
+ The deliverable is the fixes themselves, not a written review.
50
+
51
+ ## What to look for
52
+
53
+ - Style guide violations (read STYLE.md)
54
+ - Bugs, logic errors, edge cases
55
+ - Unnecessary complexity
56
+ - Missing tests
57
+ ```
58
+
59
+ Run tasks by name:
60
+
61
+ ```bash
62
+ lf review # run .lf/review.lf
63
+ lf review -x src/utils.py # add context files
64
+ lf : "fix the typo" # inline prompt, no task file
65
+ ```
66
+
67
+ All `.md` files at repo root (README, STYLE, etc.) are included as context automatically.
68
+
69
+ ## Pipelines
70
+
71
+ Chain tasks in `.lf/config.yaml`:
72
+
73
+ ```yaml
74
+ pipelines:
75
+ ship:
76
+ tasks: [implement, review, test, commit]
77
+ pr: true # open PR when done
78
+ ```
79
+
80
+ ```bash
81
+ lf ship # runs each task, auto-commits between steps
82
+ ```
83
+
84
+ ## Worktrees
85
+
86
+ Loopflow delegates worktree management to worktrunk. Use `wt` directly:
87
+
88
+ ```bash
89
+ wt list # show all worktrees
90
+ wt switch --create auth # create or switch to a worktree
91
+ wt remove auth # remove worktree + branch
92
+ ```
93
+
94
+ ## Session Tracking
95
+
96
+ Track running tasks across multiple terminals (maestro is optional):
97
+
98
+ ```bash
99
+ lf ops maestro start # optional web UI (tails logs)
100
+ lf ops status # show running sessions (reads SQLite)
101
+
102
+ # In another terminal
103
+ lf implement # auto mode task registers automatically
104
+
105
+ # Check from anywhere
106
+ lf ops status # see all running sessions
107
+ ```
108
+
109
+ Sessions write to SQLite in auto mode; the maestro UI reads the same database.
110
+
111
+ ## Configuration
112
+
113
+ ```yaml
114
+ # .lf/config.yaml
115
+ agent_model: claude:opus # Model: claude, codex, gemini (or backend:variant)
116
+ push: true # auto-push after commits
117
+ pr: false # open PR after pipelines
118
+
119
+ # Tasks that default to interactive mode (default is auto)
120
+ interactive:
121
+ - design
122
+ - iterate
123
+
124
+ ide:
125
+ warp: true
126
+ cursor: true
127
+ ```
128
+
129
+ ## Run Modes
130
+
131
+ By default, tasks run in **auto mode**: non-interactive with streaming output. This is ideal for most coding tasks and background execution. All runs append logs under `~/.lf/logs/<worktree>/`.
132
+
133
+ Use `-i` to run interactively (full chat, can interrupt) or configure per-task defaults:
134
+
135
+ ```bash
136
+ lf implement # auto mode (default)
137
+ lf design # interactive (from config)
138
+ lf implement -i # force interactive
139
+ lf design -a # force auto
140
+ lf implement & # background (shell handles it)
141
+ ```
142
+
143
+ ## Options
144
+
145
+ | Option | Description |
146
+ |--------|-------------|
147
+ | `-i, --interactive` | Run in interactive mode (override default) |
148
+ | `-a, --auto` | Run in auto mode (override default) |
149
+ | `-x, --context` | Add context files |
150
+ | `-w, --worktree` | Create worktree and run task there |
151
+ | `-c, --copy` | Copy prompt to clipboard, show token breakdown |
152
+ | `-v, --paste` | Include clipboard content in prompt |
153
+ | `-m, --model` | Choose model (backend or backend:variant) |
154
+ | `--parallel` | Run with multiple models in parallel |
155
+
156
+ ## Commands
157
+
158
+ | Command | Description |
159
+ |---------|-------------|
160
+ | `lf <task>` | Run a task from `.lf/` |
161
+ | `lf <pipeline>` | Run a pipeline |
162
+ | `lf : "prompt"` | Inline prompt |
163
+ | `lf ops compare a b` | Compare two worktree implementations |
164
+ | `wt <subcommand>` | Worktree management (worktrunk) |
165
+ | `lf ops pr create` | Open GitHub PR |
166
+ | `lf ops pr land [-a]` | Squash-merge to main |
167
+ | `lf ops land [--no-pr] [--force] [--base]` | Land locally via worktrunk |
168
+ | `lf ops commit [-p]` | Generate commit message and commit |
169
+ | `lf ops init` | Initialize repo with prompts and config |
170
+ | `lf ops install` | Install Claude Code, Codex, Gemini CLI |
171
+ | `lf ops doctor` | Check dependencies |
172
+ | `lf ops maestro start` | Start session tracking daemon |
173
+ | `lf ops maestro stop` | Stop session tracking daemon |
174
+ | `lf ops status` | Show running sessions |
@@ -0,0 +1,61 @@
1
+ [project]
2
+ name = "loopflow"
3
+ dynamic = ["version"]
4
+ description = "Arrange LLMs to code in harmony"
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ license = "MIT"
8
+ authors = [{ name = "Jack" }]
9
+ keywords = ["llm", "claude", "ai", "coding", "cli"]
10
+ classifiers = [
11
+ "Development Status :: 3 - Alpha",
12
+ "Environment :: Console",
13
+ "Intended Audience :: Developers",
14
+ "License :: OSI Approved :: MIT License",
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.10",
17
+ "Programming Language :: Python :: 3.11",
18
+ "Programming Language :: Python :: 3.12",
19
+ "Topic :: Software Development",
20
+ ]
21
+ dependencies = [
22
+ "typer>=0.9.0",
23
+ "pathspec>=0.11.0",
24
+ "pyyaml>=6.0",
25
+ "pydantic>=2.12.5",
26
+ "pydantic-ai-slim[anthropic]>=1.0.0",
27
+ "tiktoken>=0.7.0",
28
+ "fastapi>=0.115.0",
29
+ "uvicorn>=0.30.0",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ dev = [
34
+ "pytest>=7.0.0",
35
+ ]
36
+
37
+ [project.scripts]
38
+ lf = "loopflow.cli:main"
39
+
40
+ [build-system]
41
+ requires = ["hatchling"]
42
+ build-backend = "hatchling.build"
43
+
44
+ [tool.hatch.build.targets.wheel]
45
+ packages = ["src/loopflow"]
46
+ include = [
47
+ "src/loopflow/prompts/*.md",
48
+ "src/loopflow/templates/**/*.md",
49
+ "src/loopflow/templates/**/*.yaml",
50
+ ]
51
+
52
+ [tool.hatch.build.targets.sdist]
53
+ include = [
54
+ "src/loopflow",
55
+ "src/loopflow/prompts/*.md",
56
+ "src/loopflow/templates/**/*.md",
57
+ "src/loopflow/templates/**/*.yaml",
58
+ ]
59
+
60
+ [tool.hatch.version]
61
+ path = "src/loopflow/__init__.py"
@@ -0,0 +1 @@
1
+ __version__ = "0.5.2"
@@ -0,0 +1,15 @@
1
+ """Builtin prompts for loopflow commands.
2
+
3
+ These are prompts used by loopflow's own commands (lf ops pr create, etc.),
4
+ not user-defined tasks in .lf/.
5
+ """
6
+
7
+ from pathlib import Path
8
+
9
+ _BUILTINS_DIR = Path(__file__).parent
10
+
11
+
12
+ def get_builtin_prompt(name: str) -> str:
13
+ """Get a builtin prompt by name. Raises FileNotFoundError if not found."""
14
+ prompt_file = _BUILTINS_DIR / f"{name}.txt"
15
+ return prompt_file.read_text()
@@ -0,0 +1,26 @@
1
+ Generate a commit message for the staged changes.
2
+
3
+ Review the diff and write a concise commit message.
4
+
5
+ Do not ask questions. If anything is unclear, make the best assumption and proceed.
6
+
7
+ ## Output format
8
+
9
+ Return a structured response with:
10
+ - **title**: lowercase, with optional area prefix (e.g. `llm_http: add structured output`)
11
+ - **body**: brief explanation if needed, otherwise empty string
12
+
13
+ ## Title style
14
+
15
+ Titles are lowercase and concise. Use an area prefix when changes are focused on a specific module or feature area.
16
+
17
+ Examples:
18
+ - `llm_http: add structured output for pr messages`
19
+ - `pr workflow: add -a flag to commit and push`
20
+ - `fix typo in readme`
21
+
22
+ ## Body style
23
+
24
+ Keep it brief—one sentence or a few bullets if the change needs explanation. Empty string is fine for self-explanatory changes.
25
+
26
+ Most commits don't need a body. Only add one if the "why" isn't obvious from the title.
@@ -0,0 +1,48 @@
1
+ Generate a PR title and body for the changes on this branch.
2
+
3
+ Review the diff against main and summarize what changed and why.
4
+
5
+ Do not ask questions. If anything is unclear, make the best assumption and proceed.
6
+
7
+ ## Output format
8
+
9
+ Return a structured response with:
10
+ - **title**: lowercase, with optional area prefix (e.g. `llm_http: add structured output`)
11
+ - **body**: markdown with headers, code blocks for commands, and bullet lists
12
+
13
+ ## Title style
14
+
15
+ Titles are lowercase and concise. Use an area prefix when changes are focused on a specific module or feature area. The area can be new or existing.
16
+
17
+ Examples:
18
+ - `llm_http: add structured output for pr messages`
19
+ - `pr workflow: add -a flag to commit and push`
20
+ - `fix worktree cleanup on branch delete`
21
+
22
+ ## Body style
23
+
24
+ Use markdown headers to organize the body. Open with a "Usage" or "Try it" section showing commands in code blocks. Then explain what changed.
25
+
26
+ Structure:
27
+ 1. **Usage section** (header + code block) - how to try it, run it, or see it in action
28
+ 2. **Summary** - one paragraph explaining what this PR does and why
29
+ 3. **Changes** (optional) - bullet list of notable changes if helpful
30
+
31
+ Keep it medium length. Stay high-level; don't enumerate every file.
32
+
33
+ Example body:
34
+ ```
35
+ ## Usage
36
+
37
+ \`\`\`bash
38
+ lf ops pr create -a
39
+ lf ops pr update -a
40
+ \`\`\`
41
+
42
+ PR create and update now generate title/body via Claude API instead of reading from .lf/COMMIT. The -a flag adds, commits, and pushes before creating/updating.
43
+
44
+ ## Changes
45
+
46
+ - New llm_http module for structured LLM responses
47
+ - Builtin prompts stored in package, separate from user .lf/ tasks
48
+ ```
@@ -0,0 +1,97 @@
1
+ """Loopflow CLI: Arrange LLMs to code in harmony."""
2
+
3
+ import sys
4
+
5
+ import typer
6
+
7
+ from loopflow.config import ConfigError, load_config
8
+ from loopflow.context import find_worktree_root, gather_task
9
+ from loopflow.init_check import check_init_status
10
+
11
+ app = typer.Typer(
12
+ name="lf",
13
+ help="Arrange LLMs to code in harmony.",
14
+ no_args_is_help=True,
15
+ )
16
+
17
+ # Import and register subcommands
18
+ from loopflow.cli import run as run_module
19
+ from loopflow.cli import ops
20
+ from loopflow.cli import agent
21
+
22
+ app.add_typer(ops.app, name="ops")
23
+ app.add_typer(agent.app, name="agent")
24
+
25
+ # Register top-level commands
26
+ app.command(context_settings={"allow_extra_args": True, "allow_interspersed_args": True})(run_module.run)
27
+ app.command()(run_module.inline)
28
+ app.command(name="pipeline")(run_module.pipeline)
29
+ app.command()(run_module.cp)
30
+
31
+
32
+ def main():
33
+ """Entry point that supports 'lf <task>' and 'lf <pipeline>' shorthand."""
34
+ known_commands = {
35
+ "run",
36
+ "pipeline",
37
+ "inline",
38
+ "cp",
39
+ "ops",
40
+ "agent",
41
+ "--help",
42
+ "-h",
43
+ }
44
+
45
+ try:
46
+ if len(sys.argv) > 1:
47
+ first_arg = sys.argv[1]
48
+
49
+ # Inline prompt: lf : "prompt"
50
+ if first_arg == ":":
51
+ sys.argv.pop(1)
52
+ sys.argv.insert(1, "inline")
53
+ elif first_arg not in known_commands:
54
+ # Handle colon suffix: "lf implement: add logout" -> "lf implement add logout"
55
+ if first_arg.endswith(":"):
56
+ sys.argv[1] = first_arg[:-1]
57
+ name = sys.argv[1]
58
+ repo_root = find_worktree_root()
59
+ config = load_config(repo_root) if repo_root else None
60
+
61
+ has_pipeline = config and name in config.pipelines
62
+ has_task = repo_root and gather_task(repo_root, name) is not None
63
+
64
+ if has_pipeline and has_task:
65
+ typer.echo(f"Error: '{name}' exists as both a pipeline and a task", err=True)
66
+ typer.echo(f" Pipeline: defined in .lf/config.yaml", err=True)
67
+ typer.echo(f" Task: .claude/commands/{name}.md or .lf/{name}.*", err=True)
68
+ typer.echo(f"Remove one to resolve the conflict.", err=True)
69
+ raise SystemExit(1)
70
+
71
+ if has_pipeline:
72
+ sys.argv.insert(1, "pipeline")
73
+ elif has_task:
74
+ sys.argv.insert(1, "run")
75
+ else:
76
+ # Check if repo is initialized
77
+ status = check_init_status(repo_root) if repo_root else None
78
+ if status and not status.has_commands and not status.has_lf_dir:
79
+ # Uninitialized repo - suggest init
80
+ typer.echo(f"No task named '{name}' found.", err=True)
81
+ typer.echo("", err=True)
82
+ typer.echo("This repo hasn't been set up for loopflow yet.", err=True)
83
+ typer.echo("Run: lf ops init", err=True)
84
+ else:
85
+ # Initialized but task missing - suggest creating it
86
+ typer.echo(f"No task or pipeline named '{name}'", err=True)
87
+ typer.echo(f"Create: .claude/commands/{name}.md", err=True)
88
+ raise SystemExit(1)
89
+
90
+ app()
91
+ except ConfigError as e:
92
+ typer.echo(f"Error: {e}", err=True)
93
+ raise SystemExit(1)
94
+
95
+
96
+ if __name__ == "__main__":
97
+ main()