XlflowUI
XlflowUI is xlflow's dialog-safe VBA wrapper layer for simple interactive prompts and file-selection flows.
Use it when workbook code needs dialog behavior that should work in both:
- normal Excel usage by a human
- headless
xlflow run - unattended
xlflow test - AI-agent-driven development workflows
Why XlflowUI Exists
Raw MsgBox, InputBox, and file dialog calls block unattended Excel automation. XlflowUI keeps one VBA API surface while letting xlflow supply scripted responses in unattended modes.
- In
interactivemode,XlflowUIdelegates to the native VBA or Excel dialogs. - In
headless,ci,agent, andtestmodes, xlflow resolves scripted responses from runtime markers injected before VBA starts.
This lets one workbook support both autonomous agent workflows and normal Excel users.
DefaultResponse and DefaultValue are workbook-side fallbacks used when xlflow does not receive a scripted --msgbox or --inputbox value for that dialog id.
Default is the native interactive prompt default shown only when a human is using Excel interactively. DefaultValue is the separate headless fallback used only when xlflow cannot find a scripted --inputbox value.
VBA Contract
Recent xlflow new scaffolds include src/modules/Xlflow/XlflowUI.bas with these wrappers:
Public Function MsgBox(ByVal Id As String, ByVal Prompt As String, Optional ByVal Buttons As VbMsgBoxStyle = vbOKOnly, Optional ByVal Title As String = "", Optional ByVal DefaultResponse As String = "") As VbMsgBoxResult
Public Function InputBox(ByVal Id As String, ByVal Prompt As String, Optional ByVal Title As String = "", Optional ByVal Default As String = "", Optional ByVal DefaultValue As String = "") As String
Public Function GetOpenFilename(ByVal Id As String, Optional ByVal FileFilter As String = "", Optional ByVal FilterIndex As Long = 1, Optional ByVal Title As String = "", Optional ByVal ButtonText As String = "", Optional ByVal MultiSelect As Boolean = False, Optional ByVal DefaultValue As Variant) As Variant
Public Function FileDialogOpen(ByVal Id As String, Optional ByVal Title As String = "", Optional ByVal ButtonText As String = "", Optional ByVal MultiSelect As Boolean = False, Optional ByVal DefaultValue As Variant) As Variant
Public Function GetSaveAsFilename(ByVal Id As String, Optional ByVal InitialFileName As String = "", Optional ByVal FileFilter As String = "", Optional ByVal FilterIndex As Long = 1, Optional ByVal Title As String = "", Optional ByVal ButtonText As String = "", Optional ByVal DefaultValue As Variant) As Variant
Public Function FolderPicker(ByVal Id As String, Optional ByVal Title As String = "", Optional ByVal ButtonText As String = "", Optional ByVal InitialPath As String = "", Optional ByVal DefaultValue As Variant) As VariantExample:
Dim decision As VbMsgBoxResult
Dim customerName As String
decision = XlflowUI.MsgBox("confirm-save", "Save workbook?", vbYesNo + vbQuestion, "Orders")
If decision <> vbYes Then Exit Sub
customerName = XlflowUI.InputBox("customer-name", "Customer name", "Orders", "")File dialog example:
Dim sourceFiles As Variant
Dim exportPath As Variant
sourceFiles = XlflowUI.GetOpenFilename("source-files", MultiSelect:=True)
exportPath = XlflowUI.GetSaveAsFilename("export-path")Stable Dialog IDs
Every wrapper call needs a stable dialog id.
- Use semantic ids such as
confirm-save,customer-name, oroverwrite-existing. - Ids must contain at least one ASCII letter or digit.
- xlflow normalizes ids to lowercase ASCII letters and digits joined by
_. - Avoid ids that normalize to the same value, such as
confirm saveandconfirm-save.
Treat dialog ids as part of the workbook contract. Changing them breaks scripted responses and test fixtures.
CLI Response Flags
run and test both accept repeated scripted dialog responses.
--msgbox <dialog-id=result>--inputbox <dialog-id=value>--filedialog <kind>:<dialog-id>=<value>--ui-stream
Supported --msgbox result values:
abortcancelignorenookretryyes
Examples:
xlflow run Main.Run --headless --msgbox confirm-save=yes --inputbox customer-name=alice --json
xlflow test --msgbox confirm-save=ok --inputbox customer-name=test-user --json
xlflow run Main.Run --headless --filedialog get-open:source-files=C:\temp\a.txt --filedialog get-open:source-files=C:\temp\b.txt --filedialog save-as:export-path=C:\temp\out.xlsx --jsonAdd --ui-stream when you want realtime visibility into how headless dialogs resolved:
xlflow run Main.Run --headless --msgbox confirm-save=yes --inputbox customer-name=alice --ui-stream --json
xlflow test --msgbox confirm-save=ok --inputbox customer-name=test-user --ui-stream --json
xlflow run Main.Run --headless --filedialog folder:export-dir=@cancel --ui-stream --jsonSupported --filedialog kinds:
get-openforXlflowUI.GetOpenFilenamefile-openforXlflowUI.FileDialogOpensave-asforXlflowUI.GetSaveAsFilenamefolderforXlflowUI.FolderPicker
File dialog values use these rules:
- Repeat the same
kind:id=valueflag to supply multiple selected paths in order. - Use
@cancelto represent a cancelled dialog. GetOpenFilenameandFileDialogOpenreturn a Variant string array whenMultiSelect=True.- Non-multi-select wrappers return a single string or
Falseon cancel.
--ui-stream writes realtime XlflowUI summaries to stderr, not stdout, so --json stdout stays machine-readable. Example stderr lines:
xlflow: ui kind=msgbox id=confirm-save source=default result=yes
xlflow: ui kind=inputbox id=customer-name source=default value=[redacted]
xlflow: ui kind=file-open id=source-files source=scripted value=C:\temp\a.txt | C:\temp\b.txtInputBox values are redacted by default in both streamed stderr lines and final result payloads.
Output Contract
When --ui-stream is enabled:
- stderr receives realtime
XlflowUIevent summaries - stdout still contains only the final human output or JSON envelope
- final
run/testresults include top-levelui.events
Without --json, human-readable run and test output may also include a UI section summarizing those same events after execution.
Lint And Analyzer Guidance
xlflow lint reports raw MsgBox, InputBox, and file dialog usage as VB007 GUI-boundary warnings.
The intended remediation is not "never show dialogs". The intended remediation is:
- replace raw
MsgBoxwithXlflowUI.MsgBox - replace raw
InputBoxwithXlflowUI.InputBox - replace raw file picker calls with the matching
XlflowUIfile dialog wrapper - provide
--msgbox,--inputbox, and--filedialogvalues for unattended runs
Only disable VB007 with [lint].forbid_interactive_input = false for genuinely human-only projects. That setting does not make run --headless capable of answering raw dialogs.
When XlflowUI.bas is present, push also rejects bare MsgBox and InputBox calls before Excel opens. This is separate from VB007: unqualified names can bind to XlflowUI.MsgBox / XlflowUI.InputBox instead of the VBA built-ins. Use XlflowUI wrappers by default. If a module intentionally needs the native human-only dialog, write VBA.Interaction.MsgBox or VBA.Interaction.InputBox explicitly.
Design Guidance
- Use
XlflowUIonly for true user interaction points. - For machine-supplied values such as batch paths, feature flags, or automation-only inputs, prefer
xlflow run --arg, configuration cells, or deterministic configuration instead of dialog wrappers. - Use the file dialog wrappers when the same workbook flow genuinely needs both human file picking and scripted unattended execution.
- Keep dialogs thin and business-oriented. One dialog id should represent one decision or one scalar input.
- If the flow requires many fields, validation loops, or rich state, move that UX to a UserForm or worksheet-driven settings instead of chaining many
InputBoxcalls.
AI Agent Workflow
When an AI agent edits VBA that includes simple dialogs:
- replace raw
MsgBox/InputBox/ file dialog calls withXlflowUI - keep stable dialog ids in source control
- validate with
xlflow lint --json - run unattended verification with
xlflow test --msgbox ... --inputbox ... --filedialog ... --ui-stream --jsonorxlflow run --headless --msgbox ... --inputbox ... --filedialog ... --ui-stream --jsonwhen realtime dialog visibility matters; omit--ui-streamwhen only the final result matters - keep
xlflow run --interactivefor truly human-operated UI only
Debugging Headless Dialogs
If headless XlflowUI behavior is unclear, rerun with the same --msgbox / --inputbox / --filedialog values plus --ui-stream before adding extra XlflowDebug.Log or other VBA logging.
- Use realtime stderr lines to confirm dialog order and response source.
- Use final
ui.eventsfor structured post-run inspection. - If
response_source=default, verify the workbook-sideDefaultResponse/DefaultValuebehavior before changing CLI fixtures.
Future Interactive Helpers
xlflow is expected to support more interactive helper functions over time. Follow the same pattern for those additions:
- add the wrapper under
XlflowUI - preserve the normal interactive Excel behavior
- add an unattended response path through xlflow runtime injection
- teach lint/analyzer guidance to point users toward the wrapper instead of the raw VBA API