beflow 0.1.0 → 0.2.0

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.
package/README.md CHANGED
@@ -3,6 +3,10 @@
3
3
  **An AI-agent orchestration CLI that drives your issue tracker's backlog to
4
4
  shipped PRs.**
5
5
 
6
+ [![npm](https://img.shields.io/npm/v/beflow?style=flat-square)](https://www.npmjs.com/package/beflow) [![CI](https://img.shields.io/github/actions/workflow/status/corrm/beflow/ci.yml?branch=main&style=flat-square)](https://github.com/corrm/beflow/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/github/license/corrm/beflow?style=flat-square)](https://github.com/corrm/beflow/blob/main/LICENSE)
7
+
8
+ ![beflow demo](media/demo.gif)
9
+
6
10
  beflow turns work items on a project board ([Plane](https://plane.so) or
7
11
  [Linear](https://linear.app)) into agent-driven pull requests. You stay the
8
12
  captain — decide, review, merge; beflow runs the crew — investigate, spec,
@@ -13,11 +17,20 @@ run: beflow resolves a task + a repo + a contract, hands them to a coding-agent
13
17
  CLI, and writes the structured result back to the board. The agent never knows
14
18
  which tracker it's serving, so the same agent works across Plane and Linear.
15
19
 
16
- ```
17
- Tracker adapter beflow core Agent adapter
18
- (Plane | Linear) ──fetch──▶ resolve repo+agent ──run──▶ (claude | …)
19
- ▲ +job kind+run mode │
20
- └────────────────── write back report ◀────────────────┘
20
+ ```mermaid
21
+ flowchart LR
22
+ T["Tracker adapter<br/>Plane | Linear"]
23
+ subgraph C["beflow core"]
24
+ R["resolve repo + agent<br/>+ job kind + run mode"]
25
+ G["gates + policy"]
26
+ P["open / ready / block PR"]
27
+ end
28
+ A["Agent adapter<br/>claude | acpx | omp"]
29
+ T -- fetch issue --> R
30
+ R --> G --> P
31
+ P -- run in worktree --> A
32
+ A -- report --> G
33
+ C -- write back report --> T
21
34
  ```
22
35
 
23
36
  ---
@@ -50,21 +63,23 @@ bun run build # optional: compile a standalone ./dist/beflow binary
50
63
  ## Quickstart
51
64
 
52
65
  ```bash
53
- # 1. Create your config from the template and edit it
54
- cp config.example.json config.json
55
-
56
- # 2. Put your tracker API token in a gitignored .env
57
- cp .env.example .env # then fill in PLANE_API_KEY or LINEAR_API_KEY
58
-
59
- # 3. Check your environment
66
+ # 1. Set your tracker API token in your shell profile:
67
+ # zsh: echo 'export PLANE_API_KEY=...' >> ~/.zshrc && source ~/.zshrc
68
+ # bash: echo 'export PLANE_API_KEY=...' >> ~/.bashrc && source ~/.bashrc
69
+ # PowerShell (Windows):
70
+ # [System.Environment]::SetEnvironmentVariable("PLANE_API_KEY","your_token","User")
71
+ # Use LINEAR_API_KEY instead if you are on Linear.
72
+
73
+ # 2. Check your setup — creates ~/beflow/config.json on first run
60
74
  beflow doctor
75
+ # Open ~/beflow/config.json, fill in your workspace slug, project IDs, and repo paths, then re-run.
61
76
 
62
- # 4. Provision the project's board (states, labels, types, modules)
63
- beflow setup APP
77
+ # 3. Provision the board (creates the tracker project if it doesn't exist)
78
+ beflow setup <KEY> # <KEY> is the project key in your config (e.g. APP, BE, WEB)
64
79
 
65
- # 5. Run a work item, or let the daemon drive the queue
66
- beflow run APP-42 --auto
67
- beflow watch APP
80
+ # 4. Run a work item, or start the watch daemon
81
+ beflow run <KEY>-42 --auto
82
+ beflow watch <KEY>
68
83
  ```
69
84
 
70
85
  See the [config reference](docs/config.md) for every setting and
@@ -72,15 +87,44 @@ See the [config reference](docs/config.md) for every setting and
72
87
 
73
88
  ## Run modes
74
89
 
75
- | Mode | Flag | What it is |
76
- | ---------- | ---------------------------- | ------------------------------------------------------------------------------------------------------ |
77
- | Autonomous | `beflow run APP-42 --auto` | Headless. Isolated git worktree; for an implement job, opens a PR and moves the item to **In Review**. |
78
- | Supervised | `beflow run APP-42 --attend` | Interactive via acpx — you approve actions as they happen. |
79
- | Open | `beflow run APP-42 --open` | Runs in the agent's own native TUI; you're present for a multi-turn session. |
90
+ | Mode | Flag | What it is |
91
+ | ---------- | ------------------------------ | ------------------------------------------------------------------------------------------------------ |
92
+ | Autonomous | `beflow run <KEY>-42 --auto` | Headless. Isolated git worktree; for an implement job, opens a PR and moves the item to **In Review**. |
93
+ | Supervised | `beflow run <KEY>-42 --attend` | Interactive via acpx — you approve actions as they happen. |
94
+ | Open | `beflow run <KEY>-42 --open` | Runs in the agent's own native TUI; you're present for a multi-turn session. |
80
95
 
81
96
  Runs are **resumable**: each persists a run record and keeps its worktree until
82
97
  the item is Done, so an interrupted run picks up where it left off.
83
98
 
99
+ In `--auto` mode with `pr.owner: "beflow"` (the beflow-owned pipeline), beflow
100
+ gates the issue before running the agent, then owns the full PR lifecycle —
101
+ opening a draft, running the quality gate, evaluating post-run policy, and
102
+ writing back to the board — without any `gh` call from the agent itself. The
103
+ post-run policy gate supports `globs`, `agentowners`, `command`, and `off`
104
+ evaluators — see [PR ownership and policy](docs/pr-ownership-and-policy.md).
105
+
106
+ ```mermaid
107
+ flowchart TD
108
+ picks["pick up issue"] --> dgate{"decision gate<br/>(needs-decision?)"}
109
+ dgate -- held --> ni1["→ Needs Input"]
110
+ dgate -- ok --> iq{"input-quality<br/>(too thin?)"}
111
+ iq -- thin --> ni2["→ Needs Input"]
112
+ iq -- ok --> wt["create worktree beflow/&lt;key&gt;"]
113
+ wt --> ag["agent: commit + push (no gh)"]
114
+ ag --> noop{"any commits?"}
115
+ noop -- no --> failkeep["failed (keep worktree)"]
116
+ noop -- yes --> draft["beflow opens DRAFT PR"]
117
+ draft --> qg{"quality gate"}
118
+ qg -- RED after rework --> failkeep2["failed (keep draft PR)"]
119
+ qg -- green --> pol{"post-run policy"}
120
+ pol -- block --> blk["close PR + delete branch<br/>→ Needs Input"]
121
+ pol -- require_approval --> appr["enrich body, leave DRAFT<br/>→ In Review + awaits-approval note"]
122
+ pol -- allow --> al["enrich body + mark ready<br/>→ In Review"]
123
+ ```
124
+
125
+ See [PR ownership and policy](docs/pr-ownership-and-policy.md) for the full
126
+ configuration reference and policy examples.
127
+
84
128
  ## The board is the control center
85
129
 
86
130
  beflow drives a simple board and you steer from it:
@@ -89,23 +133,63 @@ beflow drives a simple board and you steer from it:
89
133
  Backlog → Todo → In Progress → In Review → Done (+ Needs Input, Cancelled)
90
134
  ```
91
135
 
92
- `beflow watch` polls the queue and dispatches Todo items up to your WIP limit,
136
+ `beflow watch` polls the queue and dispatches Todo items up to your
137
+ [WIP limit](docs/config.md#projects) (`limits.inProgress` / `limits.inReview`),
93
138
  advances merged PRs to **Done**, reworks items you label `changes-requested`,
94
139
  and answers items in **Needs Input** when you reply. See the
95
140
  [lifecycle](docs/lifecycle.md) and [operating model](docs/OPERATING-MODEL.md).
96
141
 
97
142
  ## Commands
98
143
 
99
- `run` · `watch` · `setup`/`update` · `new` · `accept` · `review` · `queue` ·
100
- `runs` · `doctor` · `gc`
144
+ | Command | What it does |
145
+ | ------------------------------------------------------------------------------ | ----------------------------------------------------- |
146
+ | [`run <key>`](docs/commands.md#run-key) | Run a work item through an agent |
147
+ | [`watch <project>`](docs/commands.md#watch-project) | Continuously poll a project's queue and dispatch work |
148
+ | [`setup` / `update <project>`](docs/commands.md#setup-project--update-project) | Provision/reconcile a project's board to the template |
149
+ | [`new <project> [template]`](docs/commands.md#new-project-template) | Author a new work item from a template |
150
+ | [`accept <project> <intake>`](docs/commands.md#accept-project-intake) | Accept an intake item into the backlog |
151
+ | [`review <key>`](docs/commands.md#review-key) | Run an agent-driven review over a work item's open PR |
152
+ | [`queue`](docs/commands.md#queue-flags) | Print the work queue across projects |
153
+ | [`runs [key]`](docs/commands.md#runs-key) | Inspect persisted run records (read-only) |
154
+ | [`doctor`](docs/commands.md#doctor---ping) | Diagnose the local beflow environment |
155
+ | [`gc`](docs/commands.md#gc-flags) | Find and prune orphaned git worktrees |
101
156
 
102
157
  Full details — flags, examples, behavior — in the
103
158
  **[command reference](docs/commands.md)**. Every command also supports `--help`.
104
159
 
160
+ ## Configuration
161
+
162
+ beflow reads its configuration from `~/beflow/config.json` — the tracker
163
+ connection, your workspace + project registry, agent definitions, and global
164
+ defaults. Running `beflow doctor` creates the file automatically on first run —
165
+ open it, fill in your workspace details, and re-run. See
166
+ [`config.example.json`](config.example.json) for a complete reference.
167
+
168
+ A project maps a key to a tracker project and the local repos its work lands in:
169
+
170
+ ```json
171
+ "projects": {
172
+ "APP": {
173
+ "name": "My App",
174
+ "plane_project_id": "…",
175
+ "root": "/path/to/your/project",
176
+ "default_repo": "main_repo",
177
+ "repos": { "main_repo": "…", "website": "…" },
178
+ "module_repo_map": { "Backend": "main_repo", "Frontend": "website" }
179
+ }
180
+ }
181
+ ```
182
+
183
+ Every key — per-project overrides, agent definitions, and the opt-in gates
184
+ (dead-letter, quality gate, SLA, CI rework, review) — is documented in the
185
+ **[config reference](docs/config.md)**. API keys are set in your shell profile,
186
+ never in `~/beflow/config.json`.
187
+
105
188
  ## Documentation
106
189
 
107
190
  - [Command reference](docs/commands.md) — every command and flag
108
191
  - [Config reference](docs/config.md) — every `config.json` setting
192
+ - [PR ownership and policy](docs/pr-ownership-and-policy.md) — beflow-owned PR creation, post-run policy gating
109
193
  - [Design](docs/DESIGN.md) — architecture and the run pipeline
110
194
  - [Lifecycle](docs/lifecycle.md) — the board as the control center
111
195
  - [Operating model](docs/OPERATING-MODEL.md) — the queue-based workflow
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "./config.schema.json",
2
+ "$schema": "https://raw.githubusercontent.com/corrm/beflow/main/config.schema.json",
3
3
  "tracker": "plane",
4
4
  "trackers": {
5
5
  "plane": {
@@ -8,9 +8,25 @@
8
8
  "apiKeyEnv": "PLANE_API_KEY"
9
9
  }
10
10
  },
11
- "defaults": {
12
- "agent": "claude",
13
- "runMode": "supervised"
11
+ "agent": "claude",
12
+ "runMode": "supervised",
13
+ "pr": {
14
+ "owner": "agent",
15
+ "baseBranch": "auto"
16
+ },
17
+ "policy": {
18
+ "evaluator": "globs",
19
+ "onBlock": "comment",
20
+ "rules": [
21
+ {
22
+ "paths": ["infra/**", "**/*.tf"],
23
+ "decision": "require_approval"
24
+ },
25
+ {
26
+ "paths": [".github/**"],
27
+ "decision": "block"
28
+ }
29
+ ]
14
30
  },
15
31
  "worktrees": {
16
32
  "dir": "~/.beflow/worktrees"
@@ -59,9 +75,23 @@
59
75
  "GUI": "main_repo",
60
76
  "Website": "website"
61
77
  },
62
- "defaults": {
63
- "agent": "claude",
64
- "runMode": "supervised"
78
+ "agent": "claude",
79
+ "runMode": "supervised"
80
+ },
81
+ "OPS": {
82
+ "name": "Ops",
83
+ "plane_project_id": "<project-uuid>",
84
+ "root": "/path/to/ops",
85
+ "default_repo": "ops_repo",
86
+ "repos": {
87
+ "ops_repo": "/path/to/ops/ops_repo"
88
+ },
89
+ "module_repo_map": {
90
+ "Infra": "ops_repo"
91
+ },
92
+ "policy": {
93
+ "evaluator": "agentowners",
94
+ "agentownersPath": ".github/AGENTOWNERS"
65
95
  }
66
96
  }
67
97
  }
@@ -46,107 +46,113 @@
46
46
  },
47
47
  "additionalProperties": false
48
48
  },
49
- "defaults": {
49
+ "agent": {
50
+ "type": "string"
51
+ },
52
+ "runMode": {
53
+ "type": "string",
54
+ "enum": ["autonomous", "supervised"]
55
+ },
56
+ "assignee": {
57
+ "type": "string"
58
+ },
59
+ "deadLetter": {
50
60
  "type": "object",
51
61
  "properties": {
52
- "agent": {
53
- "type": "string"
54
- },
55
- "runMode": {
62
+ "maxAttempts": {
63
+ "type": "number"
64
+ }
65
+ },
66
+ "additionalProperties": false
67
+ },
68
+ "inputQuality": {
69
+ "type": "object",
70
+ "properties": {
71
+ "minBodyChars": {
72
+ "type": "number"
73
+ }
74
+ },
75
+ "additionalProperties": false
76
+ },
77
+ "linkedContext": {
78
+ "type": "boolean"
79
+ },
80
+ "onManualMove": {
81
+ "type": "string",
82
+ "enum": ["yield", "abort"],
83
+ "default": "yield"
84
+ },
85
+ "pr": {
86
+ "type": "object",
87
+ "properties": {
88
+ "owner": {
56
89
  "type": "string",
57
- "enum": ["autonomous", "supervised"]
90
+ "enum": ["beflow", "agent"]
58
91
  },
59
- "assignee": {
92
+ "baseBranch": {
60
93
  "type": "string"
61
- },
62
- "deadLetter": {
63
- "type": "object",
64
- "properties": {
65
- "maxAttempts": {
66
- "type": "number"
67
- }
68
- },
69
- "additionalProperties": false
70
- },
71
- "inputQuality": {
72
- "type": "object",
73
- "properties": {
74
- "minBodyChars": {
75
- "type": "number"
76
- }
77
- },
78
- "additionalProperties": false
79
- },
80
- "linkedContext": {
94
+ }
95
+ },
96
+ "additionalProperties": false
97
+ },
98
+ "qualityGate": {
99
+ "type": "object",
100
+ "properties": {
101
+ "commands": {
102
+ "type": "array",
103
+ "items": {
104
+ "type": "string"
105
+ }
106
+ }
107
+ },
108
+ "additionalProperties": false
109
+ },
110
+ "review": {
111
+ "type": "object",
112
+ "properties": {
113
+ "enabled": {
81
114
  "type": "boolean"
82
115
  },
83
- "onManualMove": {
84
- "type": "string",
85
- "enum": ["yield", "abort"],
86
- "default": "yield"
87
- },
88
- "qualityGate": {
89
- "type": "object",
90
- "properties": {
91
- "commands": {
92
- "type": "array",
93
- "items": {
94
- "type": "string"
95
- }
96
- }
97
- },
98
- "additionalProperties": false
99
- },
100
- "review": {
101
- "type": "object",
102
- "properties": {
103
- "enabled": {
104
- "type": "boolean"
105
- },
106
- "postToPr": {
107
- "type": "boolean"
108
- }
109
- },
110
- "additionalProperties": false
116
+ "postToPr": {
117
+ "type": "boolean"
118
+ }
119
+ },
120
+ "additionalProperties": false
121
+ },
122
+ "routing": {
123
+ "type": "object",
124
+ "properties": {
125
+ "implement": {
126
+ "type": "string"
111
127
  },
112
- "routing": {
113
- "type": "object",
114
- "properties": {
115
- "implement": {
116
- "type": "string"
117
- },
118
- "spec": {
119
- "type": "string"
120
- },
121
- "triage": {
122
- "type": "string"
123
- }
124
- },
125
- "additionalProperties": false
128
+ "spec": {
129
+ "type": "string"
126
130
  },
127
- "sla": {
128
- "type": "object",
129
- "properties": {
130
- "inReviewMinutes": {
131
- "type": "number"
132
- },
133
- "needsInputMinutes": {
134
- "type": "number"
135
- }
136
- },
137
- "additionalProperties": false
131
+ "triage": {
132
+ "type": "string"
133
+ }
134
+ },
135
+ "additionalProperties": false
136
+ },
137
+ "sla": {
138
+ "type": "object",
139
+ "properties": {
140
+ "inReviewMinutes": {
141
+ "type": "number"
138
142
  },
139
- "telemetry": {
140
- "type": "object",
141
- "properties": {
142
- "inComment": {
143
- "type": "boolean"
144
- }
145
- },
146
- "additionalProperties": false
143
+ "needsInputMinutes": {
144
+ "type": "number"
145
+ }
146
+ },
147
+ "additionalProperties": false
148
+ },
149
+ "telemetry": {
150
+ "type": "object",
151
+ "properties": {
152
+ "inComment": {
153
+ "type": "boolean"
147
154
  }
148
155
  },
149
- "required": ["agent", "runMode"],
150
156
  "additionalProperties": false
151
157
  },
152
158
  "worktrees": {
@@ -201,6 +207,52 @@
201
207
  "required": ["dir"],
202
208
  "additionalProperties": false
203
209
  },
210
+ "policy": {
211
+ "type": "object",
212
+ "properties": {
213
+ "evaluator": {
214
+ "type": "string",
215
+ "enum": ["globs", "command", "agentowners", "off"]
216
+ },
217
+ "command": {
218
+ "type": "array",
219
+ "items": {
220
+ "type": "string"
221
+ }
222
+ },
223
+ "rules": {
224
+ "type": "array",
225
+ "items": {
226
+ "type": "object",
227
+ "properties": {
228
+ "paths": {
229
+ "type": "array",
230
+ "items": {
231
+ "type": "string"
232
+ }
233
+ },
234
+ "agent": {
235
+ "type": "string"
236
+ },
237
+ "decision": {
238
+ "type": "string",
239
+ "enum": ["block", "require_approval", "allow"]
240
+ }
241
+ },
242
+ "required": ["decision"],
243
+ "additionalProperties": false
244
+ }
245
+ },
246
+ "agentownersPath": {
247
+ "type": "string"
248
+ },
249
+ "onBlock": {
250
+ "type": "string",
251
+ "enum": ["comment"]
252
+ }
253
+ },
254
+ "additionalProperties": false
255
+ },
204
256
  "workspace": {
205
257
  "type": "object",
206
258
  "properties": {
@@ -222,18 +274,12 @@
222
274
  "default_repo": {
223
275
  "type": "string"
224
276
  },
225
- "defaults": {
226
- "type": "object",
227
- "properties": {
228
- "agent": {
229
- "type": "string"
230
- },
231
- "runMode": {
232
- "type": "string",
233
- "enum": ["autonomous", "supervised"]
234
- }
235
- },
236
- "additionalProperties": false
277
+ "agent": {
278
+ "type": "string"
279
+ },
280
+ "runMode": {
281
+ "type": "string",
282
+ "enum": ["autonomous", "supervised"]
237
283
  },
238
284
  "ci": {
239
285
  "type": "object",
@@ -289,6 +335,65 @@
289
335
  "plane_project_id": {
290
336
  "type": "string"
291
337
  },
338
+ "policy": {
339
+ "type": "object",
340
+ "properties": {
341
+ "evaluator": {
342
+ "type": "string",
343
+ "enum": ["globs", "command", "agentowners", "off"]
344
+ },
345
+ "command": {
346
+ "type": "array",
347
+ "items": {
348
+ "type": "string"
349
+ }
350
+ },
351
+ "rules": {
352
+ "type": "array",
353
+ "items": {
354
+ "type": "object",
355
+ "properties": {
356
+ "paths": {
357
+ "type": "array",
358
+ "items": {
359
+ "type": "string"
360
+ }
361
+ },
362
+ "agent": {
363
+ "type": "string"
364
+ },
365
+ "decision": {
366
+ "type": "string",
367
+ "enum": ["block", "require_approval", "allow"]
368
+ }
369
+ },
370
+ "required": ["decision"],
371
+ "additionalProperties": false
372
+ }
373
+ },
374
+ "agentownersPath": {
375
+ "type": "string"
376
+ },
377
+ "onBlock": {
378
+ "type": "string",
379
+ "enum": ["comment"]
380
+ }
381
+ },
382
+ "additionalProperties": false
383
+ },
384
+ "pr": {
385
+ "type": "object",
386
+ "properties": {
387
+ "owner": {
388
+ "type": "string",
389
+ "enum": ["beflow", "agent"]
390
+ },
391
+ "baseBranch": {
392
+ "type": "string"
393
+ }
394
+ },
395
+ "additionalProperties": false
396
+ },
292
397
  "qualityGate": {
293
398
  "type": "object",
294
399
  "properties": {
@@ -405,7 +510,7 @@
405
510
  }
406
511
  }
407
512
  },
408
- "required": ["tracker", "trackers", "defaults", "workspace", "projects"],
513
+ "required": ["tracker", "trackers", "agent", "runMode", "workspace", "projects"],
409
514
  "additionalProperties": false
410
515
  }
411
516
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beflow",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "An AI-agent orchestration CLI that drives your issue tracker's backlog to shipped PRs.",
5
5
  "keywords": [
6
6
  "acp",