RPA projects tend to start the same way. The client sends the process definition: a Word document with a purpose, a table of steps and their business rules, sometimes a PDF, sometimes a spreadsheet, sometimes all three. The first days go into finding out which of those steps the estate already covers, which do not exist yet, and writing the design.
A model could draft that design in a minute. The reason nobody lets it is that it will invent a workflow that sounds right. ArchiveInvoicePDF reads like something the estate has. It does not, and you find out in week three.
My day job is building GenAI platforms that run in production, and the rule there is the one you apply to any distributed system: never act on an output you cannot check. So I built the planner the other way round. The model proposes; a deterministic resolver checks every step against a catalog of the functions that exist, and a step nothing can do is reported as missing. This post walks through it on the smallest example in the repository, with the real output.
The catalog
Before planning anything, the sources are read into a catalog. FlowGlyph reads UiPath projects, SAP OData $metadata, SAP Cloud Integration iFlows, SAP Build, BPMN, n8n exports and OpenAPI documents with parsers, not with a model, and turns every workflow, service operation and API call into a typed capability: inputs, outputs, what it does to the world, and whether a retry is a repeat.
The example uses a UiPath project and an OpenAPI document, merged into one catalog:
import flowglyph uipath = flowglyph.extract("tests/fixtures/synthetic/invoices") api = flowglyph.extract("tests/fixtures/openapi/payments.yaml") uipath.merge(api).save("examples/invoice-processing/catalog") The catalog is plain files you can commit: catalog.jsonl, graph.json, a lock file, and one Markdown card per function. Eighteen capabilities in this one: four UiPath workflows, seven API operations, and seven activity types that are documented but cannot run on their own.
The requirements
The requirements file is four sentences, the kind of thing a client writes:
# Supplier invoice intake When an invoice arrives, check that the vendor exists in our records. If the amount is above 10,000 EUR, ask the finance approver before going on. Then create the invoice in the payments system, using the invoice reference so that a retry never books it twice, and archive the PDF. A PDF or a Word file works the same way: flowglyph plan reads paragraphs and tables from .pdf and .docx, one table per sheet from .xlsx and .csv, and a whole folder of them in name order. A scanned PDF without a text layer is refused, not guessed.
The plan
flowglyph plan examples/invoice-processing/requirements.md examples/invoice-processing/catalog \ -o examples/invoice-processing/out --via picks the model: the Anthropic API by default, or the coding assistant you are already signed in to (claude-code, codex, gemini, cursor), or any OpenAI-compatible server (Ollama, vLLM, LM Studio). The model never sees your sources. It sees the requirements and a shortlist of candidate functions picked by BM25 over the catalog, and it has to answer in a strict JSON Schema.
Three things happen in order:
- Shortlist. BM25 over the cards finds the candidates for each sentence of the requirements. The model is not handed eighteen functions here, and it would not be handed three thousand in a real estate either.
- Proposal. The model writes
workflow.plan.yaml: a goal, typed inputs, steps with an intent, a capability id, arguments bound to inputs or to earlier steps, conditions, and a list of assumptions. - Resolution. The resolver checks every step: the capability id exists in the catalog; every required input of that capability is filled; each argument has the type the input declares; every reference points to an earlier step. Anything that fails is a problem on the step. A step the model could not assign to any candidate is a gap.
Here is the proposal for the booking step. The model picked the API operation over the UiPath workflow, and said why:
- id: create_invoice intent: Create the invoice in the payments system, with the invoice reference as idempotency key so a retry never books it twice. capability: openapi/Payments_API/createInvoice arguments: - name: Idempotency-Key source: workflow_input value: invoice_reference - name: body source: workflow_input value: invoice after: - validate_vendor - request_approval condition: validate_vendor.out_Exists == true join: any assumptions: - I used createInvoice from the Payments API instead of uipath/Invoices/Main or BookInvoice, because it is the only candidate with key-based idempotency, which a retry-safe booking needs. - The candidate list has no capability for archiving the PDF, so that step has none assigned. That second assumption is the whole point. The archive step comes out like this:
- id: archive_pdf intent: Archive the invoice PDF once the invoice is created. No candidate capability does this; a document archive capability that takes the PDF location (and ideally the invoice reference) is missing. capability: null arguments: [] And the checked workflow, workflow.ir.yaml, says so at the top:
status: needs attention problems: [] unresolved: - archive_pdf warnings: - 'request_approval has side effects: run it with an idempotency key so retries are safe' No problems: every resolved step exists, is fully bound and typed. One unresolved step: nothing in the sources archives a PDF. One warning: the approval step changes something and nothing guarantees a retry is safe, so run it with a key. The plan is the design, the gap list and the first line of the estimate, on day one, in the client's own words.
The same thing from the Word document
In the README the same planner reads a two-page Word process definition with a four-row steps table. Two of the client's steps come back as missing:
Book emailed supplier invoices without creating duplicates, then archive the PDF Step Capability Intent validate_vendor uipath/Invoices/Steps/ValidateVendor Check that the vendor on the invoice exists in our records. notify_purchasing missing Notify purchasing that the vendor is unknown and stop processing the invoice. request_approval uipath/Invoices/Steps/RequestApproval Ask the finance approver for approval before booking a high-value invoice. create_invoice openapi/Payments_API/createInvoice Create the invoice in the payments system, keyed by the invoice reference so a retry never books it twice. archive_pdf missing Archive the invoice PDF in the document store with a 10-year retention period. Nothing notifies purchasing, nothing archives a PDF. Those two go straight into the backlog, and nothing was invented to fill them.
Opening it in Studio
The resolved part does not stay as YAML:
flowglyph compile plan/workflow.ir.yaml --catalog catalog --to xaml -o Main.xaml warning conditions are copied as written; rewrite them as Visual Basic expressions in Studio Compiled plan/book-emailed-supplier-invoices-without-creating-duplicates-then-archive-the-pdf into Main.xaml Main.xaml is a Flowchart with each resolved step as an InvokeWorkflowFile, its arguments ready to bind, a FlowDecision per condition, and a Comment where each missing step goes:
<ui:Comment DisplayName="Notify purchasing that the vendor is unknown and stop processing the invoice." Text="...: no capability does this yet" /> --to bpmn gives the process owner the same workflow as BPMN 2.0 with a diagram. A coding agent with the project's activity cards (another command, flowglyph context, writes them from the project) builds the two missing steps from there.
What it does not do
It does not judge whether a resolved step is the right one, only that it exists, fits and is typed. The model chose createInvoice over BookInvoice for a good reason and said so, but a worse choice that still type-checks would pass. Read the assumptions.
Conditions are copied as written. The resolver checks that they reference existing steps and inputs; it does not evaluate them, and the XAML compiler tells you to rewrite them as Visual Basic.
It needs a model, any of the ones above, and the quality of the proposal is the model's. What the resolver guarantees is narrower and, I think, more useful: nothing in the output exists only in the model's head.
And it is alpha. The IR is at 0.4 and may change; the adapters have run on vendor templates and synthetic projects, not on a real client estate yet.
Try it
The quickest test needs no clone and no model. It reads UiPath's own template and tells you which workflows are safe to run twice:
pip install "flowglyph[cli]" flowglyph idempotency https://github.com/UiPath/ReFrameWork --kind workflow Then the planner on your own sources:
pip install "flowglyph[all]" flowglyph extract ./your-automations -o catalog flowglyph plan requirements.md catalog -o plan --via claude-code The code, the examples and every output above are at github.com/afernandeztem/FlowGlyph, Apache-2.0.
Help shape it
The most useful thing you can send is a file it gets wrong: an issue with the XAML, the EDMX or the BPMN that broke. Use cases I have not thought of go to the repo's Discussions. And there are six good first issues, from a Power Automate adapter to an n8n example.
What I would like to know from people who have put a model in front of a real estate: how do you keep it from inventing functions, and does a gap list on day one change how you scope the work?
