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.
- loopflow-0.5.2/.gitignore +11 -0
- loopflow-0.5.2/PKG-INFO +203 -0
- loopflow-0.5.2/README.md +174 -0
- loopflow-0.5.2/pyproject.toml +61 -0
- loopflow-0.5.2/src/loopflow/__init__.py +1 -0
- loopflow-0.5.2/src/loopflow/builtins/__init__.py +15 -0
- loopflow-0.5.2/src/loopflow/builtins/commit_message.txt +26 -0
- loopflow-0.5.2/src/loopflow/builtins/pr_message.txt +48 -0
- loopflow-0.5.2/src/loopflow/cli/__init__.py +97 -0
- loopflow-0.5.2/src/loopflow/cli/agent.py +447 -0
- loopflow-0.5.2/src/loopflow/cli/commit.py +82 -0
- loopflow-0.5.2/src/loopflow/cli/compare.py +199 -0
- loopflow-0.5.2/src/loopflow/cli/land.py +215 -0
- loopflow-0.5.2/src/loopflow/cli/maestro.py +75 -0
- loopflow-0.5.2/src/loopflow/cli/meta.py +475 -0
- loopflow-0.5.2/src/loopflow/cli/ops.py +26 -0
- loopflow-0.5.2/src/loopflow/cli/pr.py +334 -0
- loopflow-0.5.2/src/loopflow/cli/run.py +533 -0
- loopflow-0.5.2/src/loopflow/cli/sessions.py +88 -0
- loopflow-0.5.2/src/loopflow/cli/status.py +49 -0
- loopflow-0.5.2/src/loopflow/config.py +131 -0
- loopflow-0.5.2/src/loopflow/context.py +283 -0
- loopflow-0.5.2/src/loopflow/design.py +48 -0
- loopflow-0.5.2/src/loopflow/files.py +242 -0
- loopflow-0.5.2/src/loopflow/frontmatter.py +216 -0
- loopflow-0.5.2/src/loopflow/git.py +202 -0
- loopflow-0.5.2/src/loopflow/init_check.py +40 -0
- loopflow-0.5.2/src/loopflow/launcher.py +596 -0
- loopflow-0.5.2/src/loopflow/llm_http.py +203 -0
- loopflow-0.5.2/src/loopflow/logging.py +71 -0
- loopflow-0.5.2/src/loopflow/maestro/__init__.py +45 -0
- loopflow-0.5.2/src/loopflow/maestro/agent.py +154 -0
- loopflow-0.5.2/src/loopflow/maestro/agent_runner.py +55 -0
- loopflow-0.5.2/src/loopflow/maestro/agents.py +199 -0
- loopflow-0.5.2/src/loopflow/maestro/api.py +231 -0
- loopflow-0.5.2/src/loopflow/maestro/collector.py +337 -0
- loopflow-0.5.2/src/loopflow/maestro/daemon.py +219 -0
- loopflow-0.5.2/src/loopflow/maestro/db.py +357 -0
- loopflow-0.5.2/src/loopflow/maestro/launchd.py +140 -0
- loopflow-0.5.2/src/loopflow/maestro/markdown.py +185 -0
- loopflow-0.5.2/src/loopflow/maestro/runner.py +501 -0
- loopflow-0.5.2/src/loopflow/maestro/session.py +56 -0
- loopflow-0.5.2/src/loopflow/maestro/triggers.py +91 -0
- loopflow-0.5.2/src/loopflow/maestro/worktree.py +96 -0
- loopflow-0.5.2/src/loopflow/pipeline.py +145 -0
- loopflow-0.5.2/src/loopflow/prompts/CHECKPOINT_MESSAGE.md +29 -0
- loopflow-0.5.2/src/loopflow/prompts/COMMIT_MESSAGE.md +24 -0
- loopflow-0.5.2/src/loopflow/publish.py +189 -0
- loopflow-0.5.2/src/loopflow/templates/PROMPTS.md +83 -0
- loopflow-0.5.2/src/loopflow/templates/STYLE.md +130 -0
- loopflow-0.5.2/src/loopflow/templates/commands/debug.md +42 -0
- loopflow-0.5.2/src/loopflow/templates/commands/design.md +58 -0
- loopflow-0.5.2/src/loopflow/templates/commands/implement.md +37 -0
- loopflow-0.5.2/src/loopflow/templates/commands/iterate.md +37 -0
- loopflow-0.5.2/src/loopflow/templates/commands/polish.md +48 -0
- loopflow-0.5.2/src/loopflow/templates/commands/review.md +69 -0
- loopflow-0.5.2/src/loopflow/templates/config.yaml +49 -0
- loopflow-0.5.2/src/loopflow/tokens.py +215 -0
- loopflow-0.5.2/src/loopflow/worktrees.py +167 -0
loopflow-0.5.2/PKG-INFO
ADDED
|
@@ -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 |
|
loopflow-0.5.2/README.md
ADDED
|
@@ -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()
|