relay-flow 0.2.6-alpha → 0.2.7-alpha
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
|
@@ -1,36 +1,160 @@
|
|
|
1
1
|
# relay-flow
|
|
2
2
|
|
|
3
|
-
Durable, graph-based agent workflow runner. A ticket is the unit of work; a workflow YAML declares nodes and routes; a durable
|
|
3
|
+
Durable, graph-based agent workflow runner. A ticket is the unit of work; a workflow YAML declares nodes and routes; a durable executor drives progression, waits, retries, and recovery. Task systems (Jira and Beads), runners (Orca and Herdr), harnesses (OpenCode and Pi), and durable executors (go-workflows and Temporal) are selectable independently.
|
|
4
4
|
|
|
5
5
|
This is a ground-up rewrite. The previous per-workflow, in-memory daemon is gone. There is no migration path and no compatibility layer.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Quick start
|
|
10
10
|
|
|
11
|
-
###
|
|
11
|
+
### 1. Install relay-flow
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|---|---|
|
|
15
|
-
| [opencode](https://opencode.ai) | Agents run in opencode sessions (harness) |
|
|
16
|
-
| [Orca](https://github.com/Necmttn/orca) CLI + app | Worktrees + terminals (runner) |
|
|
17
|
-
| `bd` CLI | Beads task-system access (required when `taskPlugin: beads`) |
|
|
18
|
-
| Dolt | External/server-backed Beads only |
|
|
19
|
-
| Jira API token | Jira REST API v3 access (required when `taskPlugin: jira`) |
|
|
20
|
-
| Go 1.24+ | Build the CLI |
|
|
13
|
+
Install the latest released CLI with Homebrew:
|
|
21
14
|
|
|
22
|
-
|
|
15
|
+
```sh
|
|
16
|
+
brew install rajpopat27/tap/relay-flow
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### 2. Install the harness extension
|
|
20
|
+
|
|
21
|
+
Choose the harness that will run your agent sessions. Both commands install the
|
|
22
|
+
same `relay-flow-plugin` package with host-specific entrypoints.
|
|
23
|
+
|
|
24
|
+
**OpenCode**
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
opencode plugin relay-flow-plugin@0.2.7-alpha
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Pi**
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
pi install npm:relay-flow-plugin@0.2.7-alpha
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Pi loads the package's `pi.ts` extension from its manifest. Do not add
|
|
37
|
+
`-e`/`--extension` to relay-flow's Pi launch command.
|
|
38
|
+
|
|
39
|
+
### 3. Initialize relay-flow
|
|
40
|
+
|
|
41
|
+
Choose one task system, runner, harness, and durable executor. This example
|
|
42
|
+
uses Jira, Orca, OpenCode, and the default embedded executor:
|
|
23
43
|
|
|
24
44
|
```sh
|
|
25
|
-
|
|
45
|
+
relay-flow init \
|
|
46
|
+
--task-plugin jira \
|
|
47
|
+
--runner-plugin orca \
|
|
48
|
+
--harness-plugin opencode
|
|
26
49
|
```
|
|
27
50
|
|
|
51
|
+
The default executor is `goworkflows` with SQLite. To use Temporal instead,
|
|
52
|
+
add `--executor-plugin temporal`, `--temporal-address <host:port>`, and
|
|
53
|
+
`--temporal-namespace <name>` to the command.
|
|
54
|
+
|
|
55
|
+
### 4. Authenticate the task system
|
|
56
|
+
|
|
57
|
+
For Jira, authenticate the selected task plugin:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
relay-flow task auth
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
For Beads, skip this command and initialize/authenticate the Beads workspace
|
|
64
|
+
with `bd` and, when needed, Dolt. See [Beads task system](#beads-task-system)
|
|
65
|
+
below.
|
|
66
|
+
|
|
67
|
+
### 5. Start the server
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
relay-flow serve --background
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 6. Register a repository
|
|
74
|
+
|
|
75
|
+
The repository must already exist in the selected runner. For Orca:
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
orca repo add --path /work/payments
|
|
79
|
+
relay-flow repo register
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
For Herdr, register the repository path directly; relay-flow creates ticket
|
|
83
|
+
worktrees lazily. The interactive registration asks for the task-system values
|
|
84
|
+
required by the selected task plugin.
|
|
85
|
+
|
|
86
|
+
### 7. Submit a workflow
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
relay-flow workflow submit --file examples/minimal-jira-task-workflow.yaml
|
|
90
|
+
relay-flow workflow list
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Replace the example workflow with
|
|
94
|
+
`examples/minimal-beads-task-workflow.yaml` when using Beads. The workflow's
|
|
95
|
+
`repos` value must match the name used during repository registration.
|
|
96
|
+
|
|
97
|
+
## Supported plugins
|
|
98
|
+
|
|
99
|
+
Each category is a replaceable boundary. Select one plugin from each category
|
|
100
|
+
at initialization; the workflow YAML and core orchestration do not change when
|
|
101
|
+
you switch an implementation.
|
|
102
|
+
|
|
103
|
+
| Category | Supported plugins | Owns |
|
|
104
|
+
|---|---|---|
|
|
105
|
+
| Task system | `jira`, `beads` | Parent tickets, mailbox subtasks, task state, labels, comments, and task configuration |
|
|
106
|
+
| Runner | `orca`, `herdr` | Ticket worktrees, environments, terminals, process liveness, and cleanup |
|
|
107
|
+
| Harness | `opencode`, `pi` | Agent launch commands, sessions, prompts, report parsing, nudges, and resume behavior |
|
|
108
|
+
| Durable executor | `goworkflows`, `temporal` | Graph progression, waits, retries, recovery, and durable execution state |
|
|
109
|
+
|
|
110
|
+
The default durable executor is `goworkflows`, which stores execution state in
|
|
111
|
+
SQLite. `temporal` uses an external Temporal server and is selected with the
|
|
112
|
+
Temporal address and namespace during `init`.
|
|
113
|
+
|
|
114
|
+
The plugin composition is explicit:
|
|
115
|
+
|
|
116
|
+
```text
|
|
117
|
+
Task system (Jira or Beads)
|
|
118
|
+
│
|
|
119
|
+
▼
|
|
120
|
+
Durable executor (go-workflows or Temporal)
|
|
121
|
+
│
|
|
122
|
+
▼
|
|
123
|
+
Runner (Orca or Herdr)
|
|
124
|
+
│
|
|
125
|
+
▼
|
|
126
|
+
Harness (OpenCode or Pi)
|
|
127
|
+
│
|
|
128
|
+
▼
|
|
129
|
+
relay-flow report transport
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The equivalent non-interactive selection is:
|
|
133
|
+
|
|
134
|
+
```sh
|
|
135
|
+
relay-flow init \
|
|
136
|
+
--task-plugin <jira|beads> \
|
|
137
|
+
--runner-plugin <orca|herdr> \
|
|
138
|
+
--harness-plugin <opencode|pi> \
|
|
139
|
+
--executor-plugin <goworkflows|temporal>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`--executor-plugin` defaults to `goworkflows`. Jira requires Jira credentials;
|
|
143
|
+
Beads requires the `bd` CLI and a configured workspace. Orca requires its CLI
|
|
144
|
+
and app; Herdr requires its CLI/server. OpenCode and Pi each require their
|
|
145
|
+
corresponding agent runtime. These integrations remain behind their small
|
|
146
|
+
contracts, so task-system fields do not leak into runners or harnesses.
|
|
147
|
+
|
|
148
|
+
## Detailed setup
|
|
149
|
+
|
|
150
|
+
### Harness configuration
|
|
151
|
+
|
|
28
152
|
OpenCode plugin configuration uses both entrypoints. The server entrypoint is listed in `opencode.json`:
|
|
29
153
|
|
|
30
154
|
```json
|
|
31
155
|
{
|
|
32
156
|
"$schema": "https://opencode.ai/config.json",
|
|
33
|
-
"plugin": ["relay-flow-plugin"]
|
|
157
|
+
"plugin": ["relay-flow-plugin@0.2.7-alpha"]
|
|
34
158
|
}
|
|
35
159
|
```
|
|
36
160
|
|
|
@@ -39,7 +163,7 @@ The native HITL approval entrypoint is listed in `.opencode/tui.json`:
|
|
|
39
163
|
```json
|
|
40
164
|
{
|
|
41
165
|
"$schema": "https://opencode.ai/tui.json",
|
|
42
|
-
"plugin": ["relay-flow-plugin"]
|
|
166
|
+
"plugin": ["relay-flow-plugin@0.2.7-alpha"]
|
|
43
167
|
}
|
|
44
168
|
```
|
|
45
169
|
|
|
@@ -55,7 +179,7 @@ Pi plugin: install the same published package manually in Pi's global package
|
|
|
55
179
|
settings before starting a Pi harness session:
|
|
56
180
|
|
|
57
181
|
```sh
|
|
58
|
-
pi install npm:relay-flow-plugin
|
|
182
|
+
pi install npm:relay-flow-plugin@0.2.7-alpha
|
|
59
183
|
```
|
|
60
184
|
|
|
61
185
|
Relay-flow does not install or configure the package automatically. Pi resolves
|
|
@@ -71,14 +195,14 @@ structured report, applies the agent/HITL nudge policy, and delivers
|
|
|
71
195
|
`reportId` comes from the harness session/message identity; `nodeVisitID` is
|
|
72
196
|
internal and is never part of either plugin payload.
|
|
73
197
|
|
|
74
|
-
###
|
|
198
|
+
### Machine setup details
|
|
75
199
|
|
|
76
200
|
```sh
|
|
77
201
|
relay-flow init
|
|
78
202
|
relay-flow task auth
|
|
79
203
|
```
|
|
80
204
|
|
|
81
|
-
`init`
|
|
205
|
+
`init` selects the task system, runner, harness, and durable executor (singleton options are automatic), writes machine config, and initializes the selected execution backend. `task auth` delegates authentication to that selected task plug-in. Jira prompts for its site, email, and masked API token, validates `/myself`, and owns the system-wide `credentials.yaml`; for scripts, pass `task auth --site`, `--email`, and `--token`. A normal init rerun refuses existing state. `relay-flow init --force` updates safe stopped instances while preserving durable and repo state.
|
|
82
206
|
|
|
83
207
|
For Beads, select the plugin explicitly when scripting setup:
|
|
84
208
|
|
|
@@ -135,7 +259,7 @@ Shows a multi-select titled `Select repositories`; use Space to select Orca repo
|
|
|
135
259
|
|
|
136
260
|
Each Jira poll uses REST v3 enhanced search and requests linked-issue status with the candidate fields. Tickets with any unfinished inward `Blocks` issue are filtered before routing; no per-ticket blocker lookup is made.
|
|
137
261
|
|
|
138
|
-
For
|
|
262
|
+
For scripted Jira registration, use `relay-flow repo register --name <name> --path <path> --set project=<project>`. Component is always derived from `--name` and cannot be overridden. Registration is rejected while another repo already holds the same canonical task scope.
|
|
139
263
|
|
|
140
264
|
### Beads task system
|
|
141
265
|
|
|
@@ -229,10 +353,7 @@ Workflows live at `~/.relay-flow/workflows/<name>.yaml` after submit. Replacemen
|
|
|
229
353
|
|
|
230
354
|
Use [`examples/config-reference.yaml`](examples/config-reference.yaml) for the complete machine configuration, [`examples/workflow-reference.yaml`](examples/workflow-reference.yaml) for the complete workflow schema, or the provider-specific minimal workflows [`examples/minimal-jira-task-workflow.yaml`](examples/minimal-jira-task-workflow.yaml) and [`examples/minimal-beads-task-workflow.yaml`](examples/minimal-beads-task-workflow.yaml). Runtime node agents should follow [`docs/agent-instructions.md`](docs/agent-instructions.md). The existing [`examples/default-story-workflow.yaml`](examples/default-story-workflow.yaml) remains a more detailed Jira Story example, while [`examples/beads-workflow.yaml`](examples/beads-workflow.yaml) shows the Beads lifecycle shape. Replace the repo name and uncomment only the optional fields you need.
|
|
231
355
|
|
|
232
|
-
Task, runner, and
|
|
233
|
-
configuration cannot run Jira and Beads simultaneously; use separate
|
|
234
|
-
`RELAY_FLOW_HOME` directories or machine configurations when both providers are
|
|
235
|
-
needed.
|
|
356
|
+
Task, runner, harness, and durable executor plugins are selected machine-wide. A single relay-flow configuration cannot run Jira and Beads simultaneously; use separate `RELAY_FLOW_HOME` directories or machine configurations when both providers are needed.
|
|
236
357
|
|
|
237
358
|
### Run
|
|
238
359
|
|
|
@@ -262,6 +383,8 @@ cleanupRunnerOnEnd: false # optional; when true the runner tears down at
|
|
|
262
383
|
taskConfig: # optional; adapter-owned; merged root → repo → workflow → node
|
|
263
384
|
filters:
|
|
264
385
|
parentStatuses: [To Do]
|
|
386
|
+
labels: ["workflow:true"]
|
|
387
|
+
assignees: ["currentUser()"] # Jira resolves this to the authenticated email.
|
|
265
388
|
|
|
266
389
|
nodes:
|
|
267
390
|
start:
|
|
@@ -271,20 +394,43 @@ nodes:
|
|
|
271
394
|
onSuccess: [{ target: coding }]
|
|
272
395
|
|
|
273
396
|
coding:
|
|
274
|
-
type: agent
|
|
275
|
-
agent: build
|
|
397
|
+
type: agent
|
|
398
|
+
agent: build
|
|
276
399
|
description: | # becomes the mailbox description and launch prompt
|
|
277
|
-
Implement the ticket.
|
|
400
|
+
Implement the ticket in the current worktree.
|
|
401
|
+
nudgePrompt: |
|
|
402
|
+
Continue working on {{ticket}}. Read the parent {{taskSystem}} ticket
|
|
403
|
+
{{ticket}} and your assigned ticket {{mailbox}} to understand the requirements. Read
|
|
404
|
+
the latest feedback, address the requested changes, and work on the next
|
|
405
|
+
bounded task slice. Return the complete report. Valid choices are:
|
|
406
|
+
{{nextSteps}}.
|
|
278
407
|
onSuccess: [{ target: reviewing, when: "work complete" }]
|
|
279
408
|
onFailure: [{ target: coding, when: "retry" }]
|
|
280
|
-
nudgePrompt: "Check edge cases for {{ticket}} before reporting." # optional custom instructions
|
|
281
409
|
|
|
282
410
|
reviewing:
|
|
411
|
+
type: agent
|
|
412
|
+
agent: plan
|
|
413
|
+
description: Review the completed implementation and report required changes.
|
|
414
|
+
nudgePrompt: |
|
|
415
|
+
Review {{ticket}}. Read the parent {{taskSystem}} ticket {{ticket}} and
|
|
416
|
+
your assigned ticket {{mailbox}} to understand the requirements. Re-check the
|
|
417
|
+
implementation and latest coding feedback, then return the complete
|
|
418
|
+
report. Valid choices are:
|
|
419
|
+
{{nextSteps}}.
|
|
420
|
+
onSuccess: [{ target: humanReview, when: "ready for human review" }]
|
|
421
|
+
onFailure: [{ target: coding, when: "changes required" }]
|
|
422
|
+
|
|
423
|
+
humanReview:
|
|
283
424
|
type: hitl
|
|
284
|
-
agent:
|
|
285
|
-
description:
|
|
286
|
-
|
|
287
|
-
|
|
425
|
+
agent: plan
|
|
426
|
+
description: Approve the reviewed implementation or request changes.
|
|
427
|
+
nudgePrompt: |
|
|
428
|
+
Review the completed work for {{ticket}} with the human. Read the parent
|
|
429
|
+
{{taskSystem}} ticket {{ticket}} and your assigned ticket {{mailbox}} to
|
|
430
|
+
understand the requirements. Return the complete report. Valid choices are:
|
|
431
|
+
{{nextSteps}}.
|
|
432
|
+
onSuccess: [{ target: end, when: "approved" }]
|
|
433
|
+
onFailure: [{ target: coding, when: "changes requested" }]
|
|
288
434
|
|
|
289
435
|
end: {}
|
|
290
436
|
```
|
|
@@ -468,7 +614,7 @@ tickets are not reopened automatically.
|
|
|
468
614
|
## Architecture
|
|
469
615
|
|
|
470
616
|
- **Task system** owns parent tickets, mailbox subtasks, task state, labels, comments, and adapter config. The parent ticket is the unit of work.
|
|
471
|
-
- **Durable workflow engine** (
|
|
617
|
+
- **Durable workflow engine** (`goworkflows` + SQLite or `temporal`) owns graph progression, waits, reports, retries, and recovery. No custom state machine.
|
|
472
618
|
- **Mailbox subtask** is one agent/HITL node's scratch space; its description defines the node's work and its comments hold the node's summary plus selected incoming feedback.
|
|
473
619
|
- **Harness** owns agent launch, session/report behavior, parsing, nudging, and resume semantics.
|
|
474
620
|
- **Runner** owns ticket worktrees/environments, terminals, liveness, and execution of harness commands.
|
|
@@ -11,10 +11,11 @@ taskConfig:
|
|
|
11
11
|
- To Do
|
|
12
12
|
issueTypes:
|
|
13
13
|
- Story
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
labels:
|
|
15
|
+
- "workflow:true"
|
|
16
|
+
assignees:
|
|
17
|
+
- currentUser()
|
|
18
|
+
# Jira resolves currentUser() to the authenticated Jira email.
|
|
18
19
|
# assignee: default-node-owner@example.com
|
|
19
20
|
# project: PAY
|
|
20
21
|
# component: api
|
|
@@ -28,48 +29,62 @@ nodes:
|
|
|
28
29
|
transitionTo:
|
|
29
30
|
parentStatus: In Progress
|
|
30
31
|
onSuccess:
|
|
31
|
-
- target:
|
|
32
|
+
- target: coding
|
|
32
33
|
when: The parent story is ready for implementation
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
coding:
|
|
35
36
|
type: agent
|
|
36
37
|
agent: build
|
|
37
|
-
description: Implement the parent story
|
|
38
|
-
|
|
38
|
+
description: Implement the parent story in the current ticket worktree.
|
|
39
|
+
nudgePrompt: |
|
|
40
|
+
Continue working on {{ticket}}. Read the parent {{taskSystem}} ticket
|
|
41
|
+
{{ticket}} and your assigned ticket {{mailbox}} to understand the requirements. Read
|
|
42
|
+
the latest feedback, address the requested changes, and work on the next
|
|
43
|
+
bounded task slice. Return the complete report. Valid choices are:
|
|
44
|
+
{{nextSteps}}.
|
|
39
45
|
taskConfig:
|
|
40
46
|
# assignee: developer@example.com
|
|
41
47
|
transitionTo:
|
|
42
48
|
taskStatus: In Progress
|
|
43
49
|
# parentStatus: In Progress
|
|
44
50
|
onSuccess:
|
|
45
|
-
- target:
|
|
51
|
+
- target: reviewing
|
|
46
52
|
when: Implementation and verification are complete
|
|
47
53
|
onFailure:
|
|
48
|
-
- target:
|
|
54
|
+
- target: coding
|
|
49
55
|
when: Implementation needs another pass
|
|
50
56
|
|
|
51
|
-
|
|
57
|
+
reviewing:
|
|
52
58
|
type: agent
|
|
53
59
|
agent: plan
|
|
54
|
-
description: Review the implementation
|
|
55
|
-
|
|
60
|
+
description: Review the completed implementation and report required changes.
|
|
61
|
+
nudgePrompt: |
|
|
62
|
+
Review {{ticket}}. Read the parent {{taskSystem}} ticket {{ticket}} and
|
|
63
|
+
your assigned ticket {{mailbox}} to understand the requirements. Re-check the
|
|
64
|
+
implementation and latest coding feedback, then return the complete
|
|
65
|
+
report. Valid choices are:
|
|
66
|
+
{{nextSteps}}.
|
|
56
67
|
taskConfig:
|
|
57
68
|
# assignee: reviewer@example.com
|
|
58
69
|
transitionTo:
|
|
59
70
|
taskStatus: In Progress
|
|
60
71
|
# parentStatus: In Review
|
|
61
72
|
onSuccess:
|
|
62
|
-
- target:
|
|
73
|
+
- target: humanReview
|
|
63
74
|
when: The changes are ready for human approval
|
|
64
75
|
onFailure:
|
|
65
|
-
- target:
|
|
76
|
+
- target: coding
|
|
66
77
|
when: Code changes are required
|
|
67
78
|
|
|
68
|
-
|
|
79
|
+
humanReview:
|
|
69
80
|
type: hitl
|
|
70
81
|
agent: plan
|
|
71
|
-
description:
|
|
72
|
-
|
|
82
|
+
description: Approve the reviewed implementation or request changes.
|
|
83
|
+
nudgePrompt: |
|
|
84
|
+
Review the completed work for {{ticket}} with the human. Read the parent
|
|
85
|
+
{{taskSystem}} ticket {{ticket}} and your assigned ticket {{mailbox}} to
|
|
86
|
+
understand the requirements. Return the complete report. Valid choices are:
|
|
87
|
+
{{nextSteps}}.
|
|
73
88
|
taskConfig:
|
|
74
89
|
# assignee: human-reviewer@example.com
|
|
75
90
|
transitionTo:
|
|
@@ -79,7 +94,7 @@ nodes:
|
|
|
79
94
|
- target: end
|
|
80
95
|
when: The human approves the review
|
|
81
96
|
onFailure:
|
|
82
|
-
- target:
|
|
97
|
+
- target: coding
|
|
83
98
|
when: The human requests code changes
|
|
84
99
|
|
|
85
100
|
end:
|
|
@@ -14,7 +14,7 @@ import (
|
|
|
14
14
|
"github.com/rajpopat27/relay-flow/internal/workflow"
|
|
15
15
|
)
|
|
16
16
|
|
|
17
|
-
const configuredPlugin = "relay-flow-plugin@0.2.
|
|
17
|
+
const configuredPlugin = "relay-flow-plugin@0.2.7-alpha"
|
|
18
18
|
|
|
19
19
|
func TestBuildCommandArgv(t *testing.T) {
|
|
20
20
|
t.Setenv("RELAY_FLOW_HOME", "/var/lib/relay-flow-test")
|