A rule engine that can't say which rule fired is a mood.
Zenith's automation is written to be read before it is trusted. Decision tables answer in rows you can point at. Workflows publish as frozen, numbered versions, and a run in flight finishes under the rules it started with. Templates name every placeholder they could not fill. And where the engine does not run something yet, the screen says so on its face.
Bilingual EN / FR · Multi-site · WCAG 2.2 AASix things a person writes down
Automation earns its keep in the months after somebody sets it up, when a different person has to work out why it did what it did. Every surface here is built for that second conversation rather than the first afternoon.
Decision tables
Rules in rows, read top to bottom. The first row whose conditions all hold decides, and later rows are not consulted — which is what makes the table auditable.
Workflows
A visual graph of nine node kinds — start, process, approval, decision, assignment, automation, notification, wait, end — each with a step key like P2 or D1 that stays stable once assigned.
Notification templates
The words the automation sends, owned by administrators rather than developers, in English and French from the first keystroke.
The inbox
What the system had to say to you — rendered at send time against the registers as they stood, so each entry is a record rather than a live query that rewrites itself.
Versions
Publishing takes a frozen, numbered snapshot and leaves the draft exactly as it was. Publishing is a snapshot, not a hand-off.
Simulation
Ask a table what it would decide, and walk a graph with sample inputs — before either is trusted with real traffic.
“Why did this request come out Urgent?”
That question deserves exactly one answer, and a decision table is the shape that gives it: rows read top to bottom, the first whose conditions all hold decides, and the decision names the row that made it. Rules a planner can read without a programmer, and argue with without a meeting.
- The answer names its row — “decided by row 2”, or “no row matched, the default answered”, or plainly “no decision” when there is neither.
- Order is the rule, so moving a row is a decision — rows move with arrows rather than drag-and-hope, because the order is the meaning.
- A new row matches everything — visibly too broad, so it gets edited rather than quietly forgotten in the middle of the table.
- Answers come from a closed set — a row cannot invent an outcome nobody listed, which is how “Urgent” and “urgent” stop being two priorities.
An approval that started under v1 finishes under v1
Changing the rules mid-flight is how an approval nobody gave gets recorded as given. So a workflow is two things sharing a name: a draft, which is the one editable head, and a list of versions, each frozen at the moment it was published. The editor only ever touches the draft; a run only ever references a version number.
- Publishing touches no run — the new version is written and the list of runs is not touched at all, so the guarantee is structural rather than a promise somebody made in a code review.
- The pin is on the row — “Published v2 · 2 still running on v1” is the rule said as a fact, where the person deciding whether to publish will read it.
- Publishing an unchanged draft is refused — a version that changes nothing is version-number inflation, and the next person reading “v7” deserves to believe seven decisions were made.
- A retry re-runs the same step on the same pinned version — never a newer one, which is the single thing an automation must never improvise.
“Workflow invalid” is a product giving up
Thirteen structural checks run against the draft graph, and every finding points at the node that failed it, in a sentence. Errors block publishing. Warnings do not — because the difference between “this cannot work” and “this will probably annoy somebody” is worth keeping.
- An approval with no approver cannot publish — that is not a workflow with a gap; it is a gate propped open that reads as a gate.
- One doorway — two Start nodes is two claims about where the process begins, and a runtime could only ever honour one of them silently.
- Every decision output is labelled — a diagram that cannot say what routes where is a picture rather than a design.
- Deleting a node takes its connectors with it — a wire to nowhere is worse than a missing box.
A notification that guesses teaches everyone to distrust every notification
A template is edited by an administrator and read by a fitter at two in the morning, and between them sits a renderer. When a placeholder cannot be resolved — mistyped, or asking for a field the event does not carry — the honest options are to say so or to guess. Zenith says so, by name, before the template is ever used.
- Unresolved placeholders stay visible in the text — left as
{{approver.name}}rather than silently blanked, so nobody ships a sentence with a hole in it. - The preview renders against real records — the author sees “Standby generator will not start on test”, not
{{workOrder.summary}}. That is the difference between checking a template and believing one. - Each event offers a closed set of tokens — what a work order can offer, what a stock alert can offer, listed rather than guessed at from memory.
- English and French from the first keystroke — subject and body are per-locale fields, not a translation pass bolted on after somebody complains.
What runs, and what is written down
Automation is the part of a maintenance system most often sold as finished and delivered as a diagram. Zenith draws the line where its own code draws it: what a person authors is built and checkable today, and what runs unattended belongs to the server phase — with every screen that touches it saying so on its face rather than in a footnote.
The product tells you where it stops
Most automation modules are bought on a demo of the designer and discovered in month four. This one prints the boundary at the foot of the page it applies to — so the question “does this actually run?” is answered before the purchase order, not after it.
- The simulator is subjunctive on purpose — nothing is created, sent or reserved, and every note it writes begins with the word would.
- The instances screen carries its own hatch — “the engine that runs steps for real is the server's half” sits under the table, permanently, not in a release note.
- The transport is missing, not the model — the inbox is already the delivery surface, rendered and timestamped; when the dispatcher lands it sends through that same door.
- Nothing is dressed up as finished — an automation step that does nothing yet is an error that blocks publishing, not a box that quietly sits there looking capable.
Everything around the rule
Seven things to watch for
A work order raised, completed or closed; a request submitted; a condition alert fired; stock below reorder; a purchase order issued. A closed list on purpose — an event is a contract, not a free-text wish.
Step IDs people can say out loud
P1, D2, A1 — numbered within the workflow and stable once assigned, so a conversation about “the second approval” has a name both people recognise.
The algorithm, drawn honestly
A start pill for the trigger, a diamond for each gate with its “no” running off to Stop, a box for each step that does work. Branches the engine cannot take are not drawn — a nicer picture of a different product helps nobody.
Reading is a timestamp
Not a flag. “When did they see it?” is the question every notification post-mortem asks — and reading twice is refused, because the first timestamp is the fact.
Failures carry their reason
A failure without one is not a failure, it is a mystery — so the reason is required, and it sits on the row next to the run that stopped.
Words owned by people
Templates are edited by administrators, not shipped in a build. Rename anything in your vocabulary and every heading follows — never what a filter matches on.
A version always means a decision
An unchanged draft cannot be published, so a version number is never inflated by somebody clicking to be sure.
Loops are reported, not run
The simulator walks the graph and stops the moment it re-enters a node it has already visited, naming it — rather than spinning quietly on somebody's behalf.
Two languages, all the way down
Every label, hint, empty state, blocker and refusal exists in English and French — including the sentence that tells you a workflow cannot publish yet.
Automation you can hand over
The person who set up your automation will leave. Everything here is built for the person who inherits it — the one who has to explain, five years on, why the system did what it did on a Tuesday nobody remembers.
Authored, then frozen
A draft is edited freely; a version is a snapshot nothing can reach back and change, and every run names the version it is living under.
Refusals name their own step
Nothing is rejected as “invalid”. Every blocker says which step, which field and what is missing, so the fix is obvious rather than a hunt.
Bilingual by birth
Full en-CA / fr-CA parity on every screen, hint, empty state and refusal — plurals handled properly, not by concatenation.
Accessible to everyone
WCAG 2.2 AA as a build rule: real tab semantics, states announced in words, and focus that moves to the field an error refers to.
Before you book the demo
Can it send a report out every Monday morning?
Does it send email?
Can a rule fire automatically on live traffic?
What can a workflow watch for?
What happens to running approvals when we change a workflow?
Is there SLA tracking and escalation?
Can we branch, or run two paths at once?
Can a step be assigned to a specific person?
What stops a half-built workflow going live?
Can we test a workflow before publishing it?
Who owns the wording of a notification?
How does this fit with the rest of Zenith?
Bring the rule nobody can explain.
Every organization has one — the priority that gets set by a rule somebody wrote in 2019, or the approval that fires for reasons three people describe three different ways. Write it down as a table with us, and we'll ask it what it would decide, in front of you, and it will name the row that answered.
