uipath codegen turns a workflow's behaviour into a runnable-shaped TaskSultan automation. It builds on two
intermediate steps: uipath ir models the workflow as an ordered tree and the expression translator decides what
each expression text means in TypeScript. The whole path is staged. It writes only into the directory you name with
--out, never into automations/ or any protected path.
#The behaviour model
uipath ir parses XAML into a typed, ordered model of behaviour: nested sequences, flowcharts and their decisions,
branches, loops, invoke calls with their argument bindings, assignments, declarations (name, type, default,
direction, scope) and try/catch/finally. Order and nesting are the point. It is a tree, not a tally.
Totality is an identity, not an aim: nodes plus attached elements plus refused elements equals the elements the
census counted and every element that is not modelled is a named refusal with its source line. An attached element
is a construct consumed as part of another, such as a using wrapper. No code is produced at this stage and the
expression text is carried verbatim.
npx tsx orchestrator/cli.ts uipath ir ./MyProject
#The expression translation
Expressions are translated from VB or C# into TypeScript where the meaning survives and refused where it does not.
The mapped operators keep their meaning: OrElse and AndAlso become short-circuit operators, VB = becomes
===, Is becomes reference equality and ^ becomes ** with explicit parentheses because the associativity
differs. A handful of members are renamed (ToString, Trim, ToLower). Every other called member is carried
verbatim, because the translator does not re-spell a name it cannot vouch for.
Refusals are named, never approximated. VB integer division, Mod and And/Or/Xor are refused because their
operand types are not visible at the expression level. Lambdas, LINQ queries, CType and TryCast, GetType
(exact type identity in .NET), date literals, numeric type suffixes and three-valued DbNull comparisons are all
refused by name. A translation also carries its runtime obligations: the names the target runtime must provide,
about which the translator claims nothing.
#What the codegen emits
The codegen lowers the model into ordered named step functions in the workflow's own order. The workflow root
becomes the platform's processTransaction hook and declarations become state fields. The platform's exception
lanes are built from the workflow's own TryCatch structure: the catch body decides the lane, the declared type
only corroborates it and an empty catch body is refused by name. Retry is declared to the runner through
defineAutomation's own retry field, never emitted as a sleep or a timer.
Output is deterministic: the same model produces byte-identical text every run. A flowchart is emitted as a graph and a state machine as a machine, rather than flattened into an order the source does not have. The emitted text is then checked with the platform's own validator against the staged source.
#The refusals it reports
Every construct the model or the translator could not handle becomes a TODO(conversion) marker inline at its own
position and is counted in the emission manifest beside the file. The accounting is an identity:
emitted_steps + refused_steps === ir_nodes and a third state is a defect.
Some whole node kinds are refused unconditionally, each with its reason. An InterruptibleWhile carries
interruption semantics the runner has no counterpart for. A TerminateWorkflow would end the run, which the
framework does not define per step. An InvokeWorkflowFile is a separate conversion unit, so the invoke is carried
as a refusal naming the workflow and its argument bindings rather than emitted as a call to something that does not
exist. Refused features include ir-refusal, condition-refused, expression-refused, lane-unattributable,
INVOKE_CODE_UNSUPPORTED and NET_METHOD_UNSUPPORTED.
npx tsx orchestrator/cli.ts uipath codegen ./MyProject --out ./staged
#Exit codes
0: emitted with nothing refused anywhere.1: emitted with refusals. The artefact declares its own incompleteness and so does the code.2: a file could not be read, or an emission was structurally invalid, or the accounting did not close.
--out is required. The codegen refuses to choose a destination for you.
#Things that catch people out
- A refusal is a result, not an error path. It is printed and counted, never silently dropped.
- The staged automation is a candidate. It is not registered, packaged or run.
- Host paths found in workflow text are replaced by a declared redaction marker and the manifest keeps the original text.