flowengine-cli 0.1.0 → 0.1.2
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.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +16 -1
- data/README.md +675 -33
- data/Rakefile +11 -12
- data/examples/01_hello_world.rb +29 -0
- data/examples/02_yes_or_no.rb +31 -0
- data/examples/03_food_preferences.rb +52 -0
- data/examples/04_event_registration.rb +75 -0
- data/examples/05_job_application.rb +103 -0
- data/examples/06_health_assessment.rb +153 -0
- data/examples/07_loan_application.rb +187 -0
- data/examples/08_intake.rb +33 -0
- data/justfile +39 -2
- data/lib/flowengine/cli/commands/graph.rb +4 -0
- data/lib/flowengine/cli/commands/run.rb +22 -28
- data/lib/flowengine/cli/commands/validate_flow.rb +26 -0
- data/lib/flowengine/cli/commands/version.rb +3 -0
- data/lib/flowengine/cli/commands.rb +4 -0
- data/lib/flowengine/cli/flow_loader.rb +12 -0
- data/lib/flowengine/cli/renderer.rb +40 -0
- data/lib/flowengine/cli/ui_helper.rb +82 -0
- data/lib/flowengine/cli/version.rb +2 -1
- data/lib/flowengine/cli.rb +3 -0
- metadata +123 -2
data/README.md
CHANGED
|
@@ -2,9 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/kigster/flowengine-cli/actions/workflows/rspec.yml) [](https://github.com/kigster/flowengine-cli/actions/workflows/rubocop.yml)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
FlowEngine CLI is a UI adapter that sits on top of the pure-Ruby `flowengine` core gem. The core gem knows nothing about terminals, databases, or web frameworks.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
> [!IMPORTANT]
|
|
8
|
+
> This gem provides the ANSI terminal CLI interface to data collection defined by [`flowengine`](https://rubygems.org/gems/flowengine)'s DSL flows.
|
|
9
|
+
|
|
10
|
+
The gem `flowengine` allows you to define complex flows that are meant to be the basis of multi-question wizards with arbitrary branching logic, and support for LLMs to shorten the wizard if the user describe their parameters in free form text. LLM then attempts to extract the structured information from that text, assigning answers to some of the questions in the flow. This allows the engine to skip some of the questions and arrive to the data completion much faster.
|
|
11
|
+
|
|
12
|
+
> [!IMPORTANT]
|
|
13
|
+
> At the moment the output of the data collection process it a multi-level JSON file. It is up to you to render it in a more user friendly way, or show it to the user as is, or save it to the database as the JSONB record.
|
|
14
|
+
|
|
15
|
+
This gem — `flowengine-cli`, as we mentioned, — is an adapter, a wrapper so to speak, around the `flowengine`, which adds the ANSI terminal support, prompts and CLI UI based on some of the gems from the [TTY Toolkit](https://ttytoolkit.org/).
|
|
16
|
+
|
|
17
|
+
The CLI gem allows you to:
|
|
18
|
+
|
|
19
|
+
* Run the CLI in the terminal with the rich TTY prompts, and upon user answering the questions save the ansnwers to a JSOM file.
|
|
20
|
+
|
|
21
|
+
* Export the logic of the DSL questions into a flow-chart as a Mermaid diagram
|
|
22
|
+
|
|
23
|
+
* Validate the flow definitions DSL.
|
|
24
|
+
|
|
25
|
+
There are multiple examples of the DSL in the `examples` folder.
|
|
26
|
+
|
|
27
|
+
Run it like so:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
flow run \
|
|
31
|
+
--output answers.json \
|
|
32
|
+
examples/07_loan_application.rb
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
8
36
|
|
|
9
37
|
## Installation
|
|
10
38
|
|
|
@@ -20,10 +48,23 @@ Or install directly:
|
|
|
20
48
|
gem install flowengine-cli
|
|
21
49
|
```
|
|
22
50
|
|
|
51
|
+
> [!IMPORTANT]
|
|
52
|
+
> This installs two executables: `flowengine-cli` (for consistency) and also `flow` which is much easier to type.
|
|
53
|
+
>
|
|
54
|
+
> ```bash
|
|
55
|
+
> $ flow --help
|
|
56
|
+
> Commands:
|
|
57
|
+
> flow graph FLOW_FILE # Export a flow definition as a Mermaid diagram
|
|
58
|
+
> flow run FLOW_FILE # Run a flow definition interactively
|
|
59
|
+
> flow validate FLOW_FILE # Validate a flow definition file
|
|
60
|
+
> flow version # Print version information
|
|
61
|
+
> ```
|
|
62
|
+
|
|
63
|
+
|
|
23
64
|
### Requirements
|
|
24
65
|
|
|
25
66
|
- Ruby >= 4.0.1
|
|
26
|
-
- [flowengine](https://github.
|
|
67
|
+
- [flowengine](https://github.com1/kigster/flowengine) ~> 0.1
|
|
27
68
|
|
|
28
69
|
## Quick Start
|
|
29
70
|
|
|
@@ -31,6 +72,9 @@ gem install flowengine-cli
|
|
|
31
72
|
|
|
32
73
|
Create a file called `intake.rb`:
|
|
33
74
|
|
|
75
|
+
> [!NOTE]
|
|
76
|
+
> We'll use examples from the tax information collection that a professional preparer might want to collect before speaking with their customer, and save a chunk of time asking basic questions that would already be answered if their customer went through this intake process.
|
|
77
|
+
|
|
34
78
|
```ruby
|
|
35
79
|
FlowEngine.define do
|
|
36
80
|
start :filing_status
|
|
@@ -70,21 +114,7 @@ end
|
|
|
70
114
|
flowengine-cli run intake.rb
|
|
71
115
|
```
|
|
72
116
|
|
|
73
|
-
The CLI walks you through each step interactively, rendering the appropriate TTY prompt for each step type. When complete, it outputs the collected answers as JSON
|
|
74
|
-
|
|
75
|
-
```json
|
|
76
|
-
{
|
|
77
|
-
"flow_file": "intake.rb",
|
|
78
|
-
"path_taken": ["filing_status", "income_types", "business_details", "summary"],
|
|
79
|
-
"answers": {
|
|
80
|
-
"filing_status": "Married",
|
|
81
|
-
"income_types": ["W2", "Business"],
|
|
82
|
-
"business_details": { "LLC": 2, "SCorp": 1, "CCorp": 0 }
|
|
83
|
-
},
|
|
84
|
-
"steps_completed": 4,
|
|
85
|
-
"completed_at": "2026-02-26T20:15:00-08:00"
|
|
86
|
-
}
|
|
87
|
-
```
|
|
117
|
+
The CLI walks you through each step interactively, rendering the appropriate TTY prompt for each step type. When complete, it outputs the collected answers as JSON.
|
|
88
118
|
|
|
89
119
|
### 3. Save results to a file
|
|
90
120
|
|
|
@@ -116,18 +146,18 @@ Loads a flow definition, presents each step as an interactive terminal prompt, a
|
|
|
116
146
|
|
|
117
147
|
```
|
|
118
148
|
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
119
|
-
┃ FlowEngine Interactive Wizard
|
|
149
|
+
┃ FlowEngine Interactive Wizard ┃
|
|
120
150
|
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
121
151
|
|
|
122
152
|
Step 1: filing_status
|
|
123
|
-
|
|
153
|
+
────────────────────────────────────────
|
|
124
154
|
What is your filing status? (Use ↑/↓ arrow keys, press Enter to select)
|
|
125
155
|
> Single
|
|
126
156
|
Married
|
|
127
157
|
HeadOfHousehold
|
|
128
158
|
|
|
129
159
|
Step 2: income_types
|
|
130
|
-
|
|
160
|
+
────────────────────────────────────────
|
|
131
161
|
Select all income types that apply: (Use ↑/↓ arrow keys, press Space to select)
|
|
132
162
|
◯ W2
|
|
133
163
|
> ◉ 1099
|
|
@@ -136,19 +166,43 @@ Loads a flow definition, presents each step as an interactive terminal prompt, a
|
|
|
136
166
|
◯ Rental
|
|
137
167
|
|
|
138
168
|
Step 3: business_details
|
|
139
|
-
|
|
169
|
+
────────────────────────────────────────
|
|
140
170
|
How many of each business type?
|
|
141
171
|
|
|
142
172
|
LLC: 2
|
|
143
173
|
SCorp: 1
|
|
144
174
|
CCorp: 0
|
|
145
175
|
|
|
176
|
+
Step 4: summary
|
|
177
|
+
────────────────────────────────────────
|
|
178
|
+
|
|
179
|
+
Thank you for completing the intake!
|
|
180
|
+
Press any key to continue...
|
|
181
|
+
|
|
146
182
|
┌ SUCCESS ─────────────────────────────────────────────────────────┐
|
|
147
183
|
│ Flow completed! │
|
|
148
184
|
└──────────────────────────────────────────────────────────────────┘
|
|
149
|
-
{ ... JSON output ... }
|
|
150
185
|
```
|
|
151
186
|
|
|
187
|
+
Then the JSON output is printed to stdout (and optionally saved to a file):
|
|
188
|
+
|
|
189
|
+
```json
|
|
190
|
+
{
|
|
191
|
+
"flow_file": "intake.rb",
|
|
192
|
+
"path_taken": ["filing_status", "income_types", "business_details", "summary"],
|
|
193
|
+
"answers": {
|
|
194
|
+
"filing_status": "Single",
|
|
195
|
+
"income_types": ["1099", "Business"],
|
|
196
|
+
"business_details": { "LLC": 2, "SCorp": 1, "CCorp": 0 },
|
|
197
|
+
"summary": null
|
|
198
|
+
},
|
|
199
|
+
"steps_completed": 4,
|
|
200
|
+
"completed_at": "2026-02-26T20:15:00-08:00"
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
> **Note:** Display steps (like `summary`) record `null` in the answers since they are informational only.
|
|
205
|
+
|
|
152
206
|
---
|
|
153
207
|
|
|
154
208
|
### `graph` -- Export Mermaid Diagram
|
|
@@ -189,6 +243,7 @@ Save to a file and render with any Mermaid-compatible tool (GitHub, VS Code, mer
|
|
|
189
243
|
|
|
190
244
|
```bash
|
|
191
245
|
flowengine-cli graph intake.rb -o flow.mmd
|
|
246
|
+
# => Diagram written to flow.mmd
|
|
192
247
|
```
|
|
193
248
|
|
|
194
249
|
---
|
|
@@ -301,12 +356,15 @@ transition to: :special_path,
|
|
|
301
356
|
)
|
|
302
357
|
```
|
|
303
358
|
|
|
304
|
-
##
|
|
359
|
+
## In-Depth Walkthrough: Tax Intake
|
|
360
|
+
|
|
361
|
+
This section walks through a realistic 17-step tax preparation intake flow, showing four different user journeys through the same flow definition. Each scenario demonstrates different branching paths, and the resulting collected data.
|
|
362
|
+
|
|
363
|
+
### The Flow Definition
|
|
305
364
|
|
|
306
|
-
|
|
365
|
+
Save this as `tax_intake.rb`:
|
|
307
366
|
|
|
308
367
|
```ruby
|
|
309
|
-
# tax_intake.rb
|
|
310
368
|
FlowEngine.define do
|
|
311
369
|
start :filing_status
|
|
312
370
|
|
|
@@ -427,25 +485,570 @@ FlowEngine.define do
|
|
|
427
485
|
end
|
|
428
486
|
|
|
429
487
|
step :review do
|
|
488
|
+
type :display
|
|
489
|
+
question "Thank you! Your intake is complete. We will be in touch shortly."
|
|
490
|
+
end
|
|
491
|
+
end
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
Now let's see how four different users travel through this flow, and what the collected data looks like for each.
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
### Scenario 1: Simple W2 Filer
|
|
499
|
+
|
|
500
|
+
A single person with only W2 income, no investments, no businesses -- the simplest path.
|
|
501
|
+
|
|
502
|
+
**Terminal session:**
|
|
503
|
+
|
|
504
|
+
```
|
|
505
|
+
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
506
|
+
┃ FlowEngine Interactive Wizard ┃
|
|
507
|
+
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
508
|
+
|
|
509
|
+
Step 1: filing_status
|
|
510
|
+
────────────────────────────────────────
|
|
511
|
+
What is your filing status for 2025?
|
|
512
|
+
> single
|
|
513
|
+
married_filing_jointly
|
|
514
|
+
married_filing_separately
|
|
515
|
+
head_of_household
|
|
516
|
+
|
|
517
|
+
Step 2: dependents
|
|
518
|
+
────────────────────────────────────────
|
|
519
|
+
How many dependents do you have? 0
|
|
520
|
+
|
|
521
|
+
Step 3: income_types
|
|
522
|
+
────────────────────────────────────────
|
|
523
|
+
Select all income types that apply to you in 2025.
|
|
524
|
+
> ◉ W2
|
|
525
|
+
◯ 1099
|
|
526
|
+
◯ Business
|
|
527
|
+
◯ Investment
|
|
528
|
+
◯ Rental
|
|
529
|
+
◯ Retirement
|
|
530
|
+
|
|
531
|
+
Step 4: state_filing
|
|
532
|
+
────────────────────────────────────────
|
|
533
|
+
Which states do you need to file in?
|
|
534
|
+
> ◉ California
|
|
535
|
+
◯ NewYork
|
|
536
|
+
◯ Texas
|
|
537
|
+
◯ Florida
|
|
538
|
+
◯ Illinois
|
|
539
|
+
◯ Other
|
|
540
|
+
|
|
541
|
+
Step 5: foreign_accounts
|
|
542
|
+
────────────────────────────────────────
|
|
543
|
+
Do you have any foreign financial accounts?
|
|
544
|
+
yes
|
|
545
|
+
> no
|
|
546
|
+
|
|
547
|
+
Step 6: deduction_types
|
|
548
|
+
────────────────────────────────────────
|
|
549
|
+
Which additional deductions apply to you?
|
|
550
|
+
◯ Medical
|
|
551
|
+
◯ Charitable
|
|
552
|
+
◯ Education
|
|
553
|
+
◯ Mortgage
|
|
554
|
+
> ◉ None
|
|
555
|
+
|
|
556
|
+
Step 7: contact_info
|
|
557
|
+
────────────────────────────────────────
|
|
558
|
+
Please provide your contact information (name, email, phone).
|
|
559
|
+
Jane Smith, jane@example.com, 415-555-1234
|
|
560
|
+
|
|
561
|
+
Step 8: review
|
|
562
|
+
────────────────────────────────────────
|
|
563
|
+
|
|
564
|
+
Thank you! Your intake is complete. We will be in touch shortly.
|
|
565
|
+
Press any key to continue...
|
|
566
|
+
|
|
567
|
+
┌ SUCCESS ─────────────────────────────────────────────────────────┐
|
|
568
|
+
│ Flow completed! │
|
|
569
|
+
└──────────────────────────────────────────────────────────────────┘
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
**Collected data (`-o simple_w2.json`):**
|
|
573
|
+
|
|
574
|
+
```json
|
|
575
|
+
{
|
|
576
|
+
"flow_file": "tax_intake.rb",
|
|
577
|
+
"path_taken": [
|
|
578
|
+
"filing_status",
|
|
579
|
+
"dependents",
|
|
580
|
+
"income_types",
|
|
581
|
+
"state_filing",
|
|
582
|
+
"foreign_accounts",
|
|
583
|
+
"deduction_types",
|
|
584
|
+
"contact_info",
|
|
585
|
+
"review"
|
|
586
|
+
],
|
|
587
|
+
"answers": {
|
|
588
|
+
"filing_status": "single",
|
|
589
|
+
"dependents": 0,
|
|
590
|
+
"income_types": ["W2"],
|
|
591
|
+
"state_filing": ["California"],
|
|
592
|
+
"foreign_accounts": "no",
|
|
593
|
+
"deduction_types": ["None"],
|
|
594
|
+
"contact_info": "Jane Smith, jane@example.com, 415-555-1234",
|
|
595
|
+
"review": null
|
|
596
|
+
},
|
|
597
|
+
"steps_completed": 8,
|
|
598
|
+
"completed_at": "2026-02-26T14:30:00-08:00"
|
|
599
|
+
}
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
**Steps skipped:** `business_count`, `complex_business_info`, `business_details`, `investment_details`, `crypto_details`, `rental_details`, `foreign_account_details`, `charitable_amount`, `charitable_documentation` -- 9 of 17 steps skipped because the user's answers didn't trigger those branches.
|
|
603
|
+
|
|
604
|
+
---
|
|
605
|
+
|
|
606
|
+
### Scenario 2: Business Owner with Crypto
|
|
607
|
+
|
|
608
|
+
A single person who owns 1 business and has crypto investments.
|
|
609
|
+
|
|
610
|
+
**Terminal session:**
|
|
611
|
+
|
|
612
|
+
```
|
|
613
|
+
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
|
614
|
+
┃ FlowEngine Interactive Wizard ┃
|
|
615
|
+
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
|
616
|
+
|
|
617
|
+
Step 1: filing_status
|
|
618
|
+
────────────────────────────────────────
|
|
619
|
+
What is your filing status for 2025?
|
|
620
|
+
> single
|
|
621
|
+
|
|
622
|
+
Step 2: dependents
|
|
623
|
+
────────────────────────────────────────
|
|
624
|
+
How many dependents do you have? 0
|
|
625
|
+
|
|
626
|
+
Step 3: income_types
|
|
627
|
+
────────────────────────────────────────
|
|
628
|
+
Select all income types that apply to you in 2025.
|
|
629
|
+
◉ W2
|
|
630
|
+
◯ 1099
|
|
631
|
+
> ◉ Business
|
|
632
|
+
◉ Investment
|
|
633
|
+
◯ Rental
|
|
634
|
+
◯ Retirement
|
|
635
|
+
|
|
636
|
+
Step 4: business_count
|
|
637
|
+
────────────────────────────────────────
|
|
638
|
+
How many total businesses do you own or are a partner in? 1
|
|
639
|
+
|
|
640
|
+
Step 5: business_details
|
|
641
|
+
────────────────────────────────────────
|
|
642
|
+
How many of each business type do you own?
|
|
643
|
+
|
|
644
|
+
RealEstate: 0
|
|
645
|
+
SCorp: 0
|
|
646
|
+
CCorp: 0
|
|
647
|
+
Trust: 0
|
|
648
|
+
LLC: 1
|
|
649
|
+
|
|
650
|
+
Step 6: investment_details
|
|
651
|
+
────────────────────────────────────────
|
|
652
|
+
What types of investments do you hold?
|
|
653
|
+
◉ Stocks
|
|
654
|
+
◯ Bonds
|
|
655
|
+
> ◉ Crypto
|
|
656
|
+
◯ RealEstate
|
|
657
|
+
◯ MutualFunds
|
|
658
|
+
|
|
659
|
+
Step 7: crypto_details
|
|
660
|
+
────────────────────────────────────────
|
|
661
|
+
Describe your cryptocurrency transactions (exchanges, approximate transaction count).
|
|
662
|
+
Coinbase and Kraken, approximately 150 trades in 2025
|
|
663
|
+
|
|
664
|
+
Step 8: state_filing
|
|
665
|
+
────────────────────────────────────────
|
|
666
|
+
Which states do you need to file in?
|
|
667
|
+
> ◉ California
|
|
668
|
+
◯ NewYork
|
|
669
|
+
◯ Texas
|
|
670
|
+
◯ Florida
|
|
671
|
+
◯ Illinois
|
|
672
|
+
◯ Other
|
|
673
|
+
|
|
674
|
+
Step 9: foreign_accounts
|
|
675
|
+
────────────────────────────────────────
|
|
676
|
+
Do you have any foreign financial accounts?
|
|
677
|
+
yes
|
|
678
|
+
> no
|
|
679
|
+
|
|
680
|
+
Step 10: deduction_types
|
|
681
|
+
────────────────────────────────────────
|
|
682
|
+
Which additional deductions apply to you?
|
|
683
|
+
◯ Medical
|
|
684
|
+
◯ Charitable
|
|
685
|
+
◯ Education
|
|
686
|
+
◯ Mortgage
|
|
687
|
+
> ◉ None
|
|
688
|
+
|
|
689
|
+
Step 11: contact_info
|
|
690
|
+
────────────────────────────────────────
|
|
691
|
+
Please provide your contact information (name, email, phone).
|
|
692
|
+
Alex Rivera, alex@startup.io, 510-555-9876
|
|
693
|
+
|
|
694
|
+
Step 12: review
|
|
695
|
+
────────────────────────────────────────
|
|
696
|
+
|
|
697
|
+
Thank you! Your intake is complete. We will be in touch shortly.
|
|
698
|
+
Press any key to continue...
|
|
699
|
+
|
|
700
|
+
┌ SUCCESS ─────────────────────────────────────────────────────────┐
|
|
701
|
+
│ Flow completed! │
|
|
702
|
+
└──────────────────────────────────────────────────────────────────┘
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
**Collected data (`-o business_crypto.json`):**
|
|
706
|
+
|
|
707
|
+
```json
|
|
708
|
+
{
|
|
709
|
+
"flow_file": "tax_intake.rb",
|
|
710
|
+
"path_taken": [
|
|
711
|
+
"filing_status",
|
|
712
|
+
"dependents",
|
|
713
|
+
"income_types",
|
|
714
|
+
"business_count",
|
|
715
|
+
"business_details",
|
|
716
|
+
"investment_details",
|
|
717
|
+
"crypto_details",
|
|
718
|
+
"state_filing",
|
|
719
|
+
"foreign_accounts",
|
|
720
|
+
"deduction_types",
|
|
721
|
+
"contact_info",
|
|
722
|
+
"review"
|
|
723
|
+
],
|
|
724
|
+
"answers": {
|
|
725
|
+
"filing_status": "single",
|
|
726
|
+
"dependents": 0,
|
|
727
|
+
"income_types": ["W2", "Business", "Investment"],
|
|
728
|
+
"business_count": 1,
|
|
729
|
+
"business_details": {
|
|
730
|
+
"RealEstate": 0,
|
|
731
|
+
"SCorp": 0,
|
|
732
|
+
"CCorp": 0,
|
|
733
|
+
"Trust": 0,
|
|
734
|
+
"LLC": 1
|
|
735
|
+
},
|
|
736
|
+
"investment_details": ["Stocks", "Crypto"],
|
|
737
|
+
"crypto_details": "Coinbase and Kraken, approximately 150 trades in 2025",
|
|
738
|
+
"state_filing": ["California"],
|
|
739
|
+
"foreign_accounts": "no",
|
|
740
|
+
"deduction_types": ["None"],
|
|
741
|
+
"contact_info": "Alex Rivera, alex@startup.io, 510-555-9876",
|
|
742
|
+
"review": null
|
|
743
|
+
},
|
|
744
|
+
"steps_completed": 12,
|
|
745
|
+
"completed_at": "2026-02-26T15:45:00-08:00"
|
|
746
|
+
}
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
Notice how selecting "Business" at `income_types` triggered the `business_count` -> `business_details` branch, and selecting "Investment" continued the flow into `investment_details`. Since the user selected "Crypto" there, the `crypto_details` step was reached. The engine evaluated transitions top-to-bottom, taking the first match.
|
|
750
|
+
|
|
751
|
+
---
|
|
752
|
+
|
|
753
|
+
### Scenario 3: Married Investor with Rentals and Foreign Accounts
|
|
754
|
+
|
|
755
|
+
A married person filing jointly, with investments, rental properties, and foreign bank accounts.
|
|
756
|
+
|
|
757
|
+
**Collected data (`-o married_investor.json`):**
|
|
758
|
+
|
|
759
|
+
```json
|
|
760
|
+
{
|
|
761
|
+
"flow_file": "tax_intake.rb",
|
|
762
|
+
"path_taken": [
|
|
763
|
+
"filing_status",
|
|
764
|
+
"dependents",
|
|
765
|
+
"income_types",
|
|
766
|
+
"investment_details",
|
|
767
|
+
"rental_details",
|
|
768
|
+
"state_filing",
|
|
769
|
+
"foreign_accounts",
|
|
770
|
+
"foreign_account_details",
|
|
771
|
+
"deduction_types",
|
|
772
|
+
"charitable_amount",
|
|
773
|
+
"contact_info",
|
|
774
|
+
"review"
|
|
775
|
+
],
|
|
776
|
+
"answers": {
|
|
777
|
+
"filing_status": "married_filing_jointly",
|
|
778
|
+
"dependents": 2,
|
|
779
|
+
"income_types": ["W2", "Investment", "Rental"],
|
|
780
|
+
"investment_details": ["Stocks", "Bonds", "MutualFunds"],
|
|
781
|
+
"rental_details": {
|
|
782
|
+
"Residential": 2,
|
|
783
|
+
"Commercial": 0,
|
|
784
|
+
"Vacation": 1
|
|
785
|
+
},
|
|
786
|
+
"state_filing": ["California", "NewYork"],
|
|
787
|
+
"foreign_accounts": "yes",
|
|
788
|
+
"foreign_account_details": 3,
|
|
789
|
+
"deduction_types": ["Medical", "Charitable", "Mortgage"],
|
|
790
|
+
"charitable_amount": 3500,
|
|
791
|
+
"contact_info": "Maria & Carlos Reyes, reyes@email.com, 212-555-4567",
|
|
792
|
+
"review": null
|
|
793
|
+
},
|
|
794
|
+
"steps_completed": 12,
|
|
795
|
+
"completed_at": "2026-02-26T16:20:00-08:00"
|
|
796
|
+
}
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
Key branching decisions in this path:
|
|
800
|
+
|
|
801
|
+
1. **`income_types`** -- No "Business" was selected, so `business_count`/`business_details` were skipped entirely. "Investment" was the first matching rule, so the flow went to `investment_details`.
|
|
802
|
+
2. **`investment_details`** -- No "Crypto", but "Rental" was in `income_types`, so the flow continued to `rental_details`.
|
|
803
|
+
3. **`foreign_accounts`** -- User answered "yes", triggering the `foreign_account_details` step.
|
|
804
|
+
4. **`deduction_types`** -- "Charitable" was selected, activating the `charitable_amount` step. But the amount (3,500) was not greater than 5,000, so `charitable_documentation` was skipped.
|
|
805
|
+
|
|
806
|
+
---
|
|
807
|
+
|
|
808
|
+
### Scenario 4: Complex Multi-Business Filer with Charitable Donations
|
|
809
|
+
|
|
810
|
+
A head of household with 4 businesses, investments, rentals, foreign accounts, and over $5,000 in charitable giving -- the longest possible path through the flow.
|
|
811
|
+
|
|
812
|
+
**Collected data (`-o complex_filer.json`):**
|
|
813
|
+
|
|
814
|
+
```json
|
|
815
|
+
{
|
|
816
|
+
"flow_file": "tax_intake.rb",
|
|
817
|
+
"path_taken": [
|
|
818
|
+
"filing_status",
|
|
819
|
+
"dependents",
|
|
820
|
+
"income_types",
|
|
821
|
+
"business_count",
|
|
822
|
+
"complex_business_info",
|
|
823
|
+
"business_details",
|
|
824
|
+
"investment_details",
|
|
825
|
+
"crypto_details",
|
|
826
|
+
"rental_details",
|
|
827
|
+
"state_filing",
|
|
828
|
+
"foreign_accounts",
|
|
829
|
+
"foreign_account_details",
|
|
830
|
+
"deduction_types",
|
|
831
|
+
"charitable_amount",
|
|
832
|
+
"charitable_documentation",
|
|
833
|
+
"contact_info",
|
|
834
|
+
"review"
|
|
835
|
+
],
|
|
836
|
+
"answers": {
|
|
837
|
+
"filing_status": "head_of_household",
|
|
838
|
+
"dependents": 3,
|
|
839
|
+
"income_types": ["W2", "1099", "Business", "Investment", "Rental", "Retirement"],
|
|
840
|
+
"business_count": 4,
|
|
841
|
+
"complex_business_info": "Primary EIN: 12-3456789. Two LLCs (consulting, real estate), one S-Corp (software), one C-Corp (manufacturing)",
|
|
842
|
+
"business_details": {
|
|
843
|
+
"RealEstate": 1,
|
|
844
|
+
"SCorp": 1,
|
|
845
|
+
"CCorp": 1,
|
|
846
|
+
"Trust": 0,
|
|
847
|
+
"LLC": 2
|
|
848
|
+
},
|
|
849
|
+
"investment_details": ["Stocks", "Bonds", "Crypto", "RealEstate", "MutualFunds"],
|
|
850
|
+
"crypto_details": "Binance and Coinbase, ~400 transactions. Includes DeFi staking and NFT sales.",
|
|
851
|
+
"rental_details": {
|
|
852
|
+
"Residential": 3,
|
|
853
|
+
"Commercial": 1,
|
|
854
|
+
"Vacation": 0
|
|
855
|
+
},
|
|
856
|
+
"state_filing": ["California", "Texas", "Florida"],
|
|
857
|
+
"foreign_accounts": "yes",
|
|
858
|
+
"foreign_account_details": 5,
|
|
859
|
+
"deduction_types": ["Medical", "Charitable", "Education", "Mortgage"],
|
|
860
|
+
"charitable_amount": 12000,
|
|
861
|
+
"charitable_documentation": "Red Cross $5,000; Habitat for Humanity $4,000; Local food bank $3,000",
|
|
862
|
+
"contact_info": "David Park, dpark@enterprise.com, 650-555-8901",
|
|
863
|
+
"review": null
|
|
864
|
+
},
|
|
865
|
+
"steps_completed": 17,
|
|
866
|
+
"completed_at": "2026-02-26T17:05:00-08:00"
|
|
867
|
+
}
|
|
868
|
+
```
|
|
869
|
+
|
|
870
|
+
This user hit all 17 steps -- every branch was activated:
|
|
871
|
+
|
|
872
|
+
| Branch Trigger | Rule | Steps Activated |
|
|
873
|
+
|---|---|---|
|
|
874
|
+
| "Business" selected in `income_types` | `contains(:income_types, "Business")` | `business_count` |
|
|
875
|
+
| `business_count` > 2 | `greater_than(:business_count, 2)` | `complex_business_info` |
|
|
876
|
+
| "Investment" selected in `income_types` | `contains(:income_types, "Investment")` | `investment_details` |
|
|
877
|
+
| "Crypto" selected in `investment_details` | `contains(:investment_details, "Crypto")` | `crypto_details` |
|
|
878
|
+
| "Rental" selected in `income_types` | `contains(:income_types, "Rental")` | `rental_details` |
|
|
879
|
+
| "yes" for `foreign_accounts` | `equals(:foreign_accounts, "yes")` | `foreign_account_details` |
|
|
880
|
+
| "Charitable" selected in `deduction_types` | `contains(:deduction_types, "Charitable")` | `charitable_amount` |
|
|
881
|
+
| `charitable_amount` > 5000 | `greater_than(:charitable_amount, 5000)` | `charitable_documentation` |
|
|
882
|
+
|
|
883
|
+
---
|
|
884
|
+
|
|
885
|
+
### Comparing the Paths
|
|
886
|
+
|
|
887
|
+
| | Scenario 1 | Scenario 2 | Scenario 3 | Scenario 4 |
|
|
888
|
+
|---|---|---|---|---|
|
|
889
|
+
| **Persona** | Simple W2 | Business + Crypto | Married Investor | Complex Filer |
|
|
890
|
+
| **Steps completed** | 8 | 12 | 12 | 17 (all) |
|
|
891
|
+
| **Steps skipped** | 9 | 5 | 5 | 0 |
|
|
892
|
+
| **Business branch** | -- | Yes (1 biz) | -- | Yes (4 biz + complex) |
|
|
893
|
+
| **Investment branch** | -- | Yes | Yes | Yes |
|
|
894
|
+
| **Crypto sub-branch** | -- | Yes | -- | Yes |
|
|
895
|
+
| **Rental branch** | -- | -- | Yes | Yes |
|
|
896
|
+
| **Foreign accounts** | -- | -- | Yes | Yes |
|
|
897
|
+
| **Charitable branch** | -- | -- | Partial (< $5k) | Full (> $5k) |
|
|
898
|
+
|
|
899
|
+
## In-Depth Walkthrough: Customer Onboarding
|
|
900
|
+
|
|
901
|
+
Tax intake isn't the only use case. Here is a customer onboarding flow showing different step types.
|
|
902
|
+
|
|
903
|
+
Save as `onboarding.rb`:
|
|
904
|
+
|
|
905
|
+
```ruby
|
|
906
|
+
FlowEngine.define do
|
|
907
|
+
start :welcome
|
|
908
|
+
|
|
909
|
+
step :welcome do
|
|
910
|
+
type :display
|
|
911
|
+
question "Welcome to Acme Corp onboarding! We'll collect a few details to get you set up."
|
|
912
|
+
transition to: :account_type
|
|
913
|
+
end
|
|
914
|
+
|
|
915
|
+
step :account_type do
|
|
916
|
+
type :single_select
|
|
917
|
+
question "What type of account are you creating?"
|
|
918
|
+
options %w[Personal Business Enterprise]
|
|
919
|
+
transition to: :company_info, if_rule: any(
|
|
920
|
+
equals(:account_type, "Business"),
|
|
921
|
+
equals(:account_type, "Enterprise")
|
|
922
|
+
)
|
|
923
|
+
transition to: :personal_info
|
|
924
|
+
end
|
|
925
|
+
|
|
926
|
+
step :company_info do
|
|
927
|
+
type :text
|
|
928
|
+
question "What is your company name?"
|
|
929
|
+
transition to: :team_size
|
|
930
|
+
end
|
|
931
|
+
|
|
932
|
+
step :team_size do
|
|
933
|
+
type :number
|
|
934
|
+
question "How many team members will use the platform?"
|
|
935
|
+
transition to: :features
|
|
936
|
+
end
|
|
937
|
+
|
|
938
|
+
step :personal_info do
|
|
430
939
|
type :text
|
|
431
|
-
question "
|
|
940
|
+
question "What is your full name?"
|
|
941
|
+
transition to: :features
|
|
942
|
+
end
|
|
943
|
+
|
|
944
|
+
step :features do
|
|
945
|
+
type :multi_select
|
|
946
|
+
question "Which features are you interested in?"
|
|
947
|
+
options %w[Analytics Reporting API Integrations Support]
|
|
948
|
+
transition to: :enterprise_sla, if_rule: all(
|
|
949
|
+
equals(:account_type, "Enterprise"),
|
|
950
|
+
contains(:features, "Support")
|
|
951
|
+
)
|
|
952
|
+
transition to: :confirm
|
|
953
|
+
end
|
|
954
|
+
|
|
955
|
+
step :enterprise_sla do
|
|
956
|
+
type :boolean
|
|
957
|
+
question "Do you require an SLA agreement?"
|
|
958
|
+
transition to: :confirm
|
|
959
|
+
end
|
|
960
|
+
|
|
961
|
+
step :confirm do
|
|
962
|
+
type :display
|
|
963
|
+
question "All set! Your account will be provisioned shortly."
|
|
432
964
|
end
|
|
433
965
|
end
|
|
434
966
|
```
|
|
435
967
|
|
|
436
|
-
Run
|
|
968
|
+
**Run and save:**
|
|
437
969
|
|
|
438
970
|
```bash
|
|
439
|
-
flowengine-cli run
|
|
971
|
+
flowengine-cli run onboarding.rb -o onboarding_result.json
|
|
972
|
+
```
|
|
973
|
+
|
|
974
|
+
**Example: Enterprise user who wants Support + SLA:**
|
|
975
|
+
|
|
976
|
+
```json
|
|
977
|
+
{
|
|
978
|
+
"flow_file": "onboarding.rb",
|
|
979
|
+
"path_taken": [
|
|
980
|
+
"welcome",
|
|
981
|
+
"account_type",
|
|
982
|
+
"company_info",
|
|
983
|
+
"team_size",
|
|
984
|
+
"features",
|
|
985
|
+
"enterprise_sla",
|
|
986
|
+
"confirm"
|
|
987
|
+
],
|
|
988
|
+
"answers": {
|
|
989
|
+
"welcome": null,
|
|
990
|
+
"account_type": "Enterprise",
|
|
991
|
+
"company_info": "Globex Corporation",
|
|
992
|
+
"team_size": 50,
|
|
993
|
+
"features": ["Analytics", "API", "Support"],
|
|
994
|
+
"enterprise_sla": true,
|
|
995
|
+
"confirm": null
|
|
996
|
+
},
|
|
997
|
+
"steps_completed": 7,
|
|
998
|
+
"completed_at": "2026-02-26T18:00:00-08:00"
|
|
999
|
+
}
|
|
440
1000
|
```
|
|
441
1001
|
|
|
442
|
-
|
|
1002
|
+
**Example: Personal user:**
|
|
1003
|
+
|
|
1004
|
+
```json
|
|
1005
|
+
{
|
|
1006
|
+
"flow_file": "onboarding.rb",
|
|
1007
|
+
"path_taken": [
|
|
1008
|
+
"welcome",
|
|
1009
|
+
"account_type",
|
|
1010
|
+
"personal_info",
|
|
1011
|
+
"features",
|
|
1012
|
+
"confirm"
|
|
1013
|
+
],
|
|
1014
|
+
"answers": {
|
|
1015
|
+
"welcome": null,
|
|
1016
|
+
"account_type": "Personal",
|
|
1017
|
+
"personal_info": "Jordan Lee",
|
|
1018
|
+
"features": ["Analytics", "Reporting"],
|
|
1019
|
+
"confirm": null
|
|
1020
|
+
},
|
|
1021
|
+
"steps_completed": 5,
|
|
1022
|
+
"completed_at": "2026-02-26T18:05:00-08:00"
|
|
1023
|
+
}
|
|
1024
|
+
```
|
|
1025
|
+
|
|
1026
|
+
The Personal user skipped `company_info`, `team_size`, and `enterprise_sla` entirely -- those steps were never reached because the transition rules didn't match.
|
|
1027
|
+
|
|
1028
|
+
## Graph Visualization Examples
|
|
1029
|
+
|
|
1030
|
+
### Validate, then visualize
|
|
1031
|
+
|
|
1032
|
+
A typical workflow is to validate first, then export the graph:
|
|
443
1033
|
|
|
444
1034
|
```bash
|
|
445
|
-
flowengine-cli
|
|
1035
|
+
$ flowengine-cli validate tax_intake.rb
|
|
1036
|
+
Flow definition is valid!
|
|
1037
|
+
Start step: filing_status
|
|
1038
|
+
Total steps: 17
|
|
1039
|
+
Steps: filing_status, dependents, income_types, business_count,
|
|
1040
|
+
complex_business_info, business_details, investment_details,
|
|
1041
|
+
crypto_details, rental_details, state_filing, foreign_accounts,
|
|
1042
|
+
foreign_account_details, deduction_types, charitable_amount,
|
|
1043
|
+
charitable_documentation, contact_info, review
|
|
1044
|
+
|
|
1045
|
+
$ flowengine-cli graph tax_intake.rb -o tax_flow.mmd
|
|
1046
|
+
Diagram written to tax_flow.mmd
|
|
446
1047
|
```
|
|
447
1048
|
|
|
448
|
-
|
|
1049
|
+
### Full Mermaid diagram for tax intake
|
|
1050
|
+
|
|
1051
|
+
The exported Mermaid diagram for the 17-step tax intake:
|
|
449
1052
|
|
|
450
1053
|
```mermaid
|
|
451
1054
|
flowchart TD
|
|
@@ -493,9 +1096,11 @@ flowchart TD
|
|
|
493
1096
|
charitable_documentation --> contact_info
|
|
494
1097
|
contact_info["Please provide your contact information..."]
|
|
495
1098
|
contact_info --> review
|
|
496
|
-
review["Thank you!
|
|
1099
|
+
review["Thank you! Your intake is complete."]
|
|
497
1100
|
```
|
|
498
1101
|
|
|
1102
|
+
Paste this into [mermaid.live](https://mermaid.live), a GitHub Markdown file, or any Mermaid-compatible renderer to see the flow as a visual graph.
|
|
1103
|
+
|
|
499
1104
|
## Architecture
|
|
500
1105
|
|
|
501
1106
|
```
|
|
@@ -528,6 +1133,43 @@ The core `flowengine` gem has **zero UI dependencies**. It provides the DSL, rul
|
|
|
528
1133
|
3. **Drives** the engine loop until completion
|
|
529
1134
|
4. **Outputs** results as structured JSON
|
|
530
1135
|
|
|
1136
|
+
### JSON Output Structure
|
|
1137
|
+
|
|
1138
|
+
Every `run` command produces JSON with a consistent structure:
|
|
1139
|
+
|
|
1140
|
+
```json
|
|
1141
|
+
{
|
|
1142
|
+
"flow_file": "path/to/flow.rb",
|
|
1143
|
+
"path_taken": ["step_a", "step_b", "step_c"],
|
|
1144
|
+
"answers": {
|
|
1145
|
+
"step_a": "<value depends on step type>",
|
|
1146
|
+
"step_b": "<value depends on step type>"
|
|
1147
|
+
},
|
|
1148
|
+
"steps_completed": 3,
|
|
1149
|
+
"completed_at": "2026-02-26T20:15:00-08:00"
|
|
1150
|
+
}
|
|
1151
|
+
```
|
|
1152
|
+
|
|
1153
|
+
| Field | Type | Description |
|
|
1154
|
+
|-------|------|-------------|
|
|
1155
|
+
| `flow_file` | `String` | The flow definition file that was executed |
|
|
1156
|
+
| `path_taken` | `Array<String>` | Ordered list of step IDs the user visited |
|
|
1157
|
+
| `answers` | `Hash` | Map of step ID to the user's answer (type varies by step) |
|
|
1158
|
+
| `steps_completed` | `Integer` | Total number of steps the user went through |
|
|
1159
|
+
| `completed_at` | `String` | ISO 8601 timestamp of when the flow finished |
|
|
1160
|
+
|
|
1161
|
+
**Answer types by step:**
|
|
1162
|
+
|
|
1163
|
+
| Step Type | Answer Type | Example |
|
|
1164
|
+
|-----------|-------------|---------|
|
|
1165
|
+
| `:single_select` | `String` | `"Married"` |
|
|
1166
|
+
| `:multi_select` | `Array<String>` | `["W2", "Business"]` |
|
|
1167
|
+
| `:number_matrix` | `Hash<String, Integer>` | `{"LLC": 2, "SCorp": 1}` |
|
|
1168
|
+
| `:text` | `String` | `"Jane Smith, jane@example.com"` |
|
|
1169
|
+
| `:number` | `Integer` | `42` |
|
|
1170
|
+
| `:boolean` | `Boolean` | `true` |
|
|
1171
|
+
| `:display` | `null` | `null` |
|
|
1172
|
+
|
|
531
1173
|
## Development
|
|
532
1174
|
|
|
533
1175
|
```bash
|