bot.describe(): Mermaid diagram or JSON graph
- One
subgraphper DSL flow. The entry node (▶) lists every trigger that starts it (bot.use,bot.when(trigger, flow), abot.conversationtrigger). Withbot.when(trigger, flow)the flow’s own trigger is not routed, and the diagram shows that. say,ask(→ state key, ⏱ when the step has its own timeout,✓schemawhen it validates with aschema),do(with the function name if it has one:do: saveUser()),media(with its kind:media (document): ...),choose(a diamond; options are arrows labelled1) Label, like the menu the user sees),form(its fields and state key),guard(guard: isAdmin(), with✗→ targetwhen it redirects),use(the sub-flow drawn inline, returning to the next step),delay(.delay()steps; a{ delay }option is appended to its step’s label),goto(a dotted arrow to the target flow) andend.- An option’s
then:is its own node when it is an action, or a nested subgraph that returns to the parent’s next step when it is a sub-flow. An option’sgotois an arrow to its target flow. - The flow’s
.timeout()and.persistent()go in the subgraph title. - A
gototo a flow that does not exist is drawn as amissing: namenode. - Steps after an unconditional
gotohave no incoming arrow (visible dead code). - Async conversations (
bot.conversation(name, fn)) are opaque: one node with their triggers. - User text is escaped with Mermaid entity codes, so it cannot break a
label or inject
%%{init}%%directives. Node ids (f0_in,f0_s3,f0_end…) are stable and the same in Mermaid, JSON and lint results.
bot.lint(): static checks
{ code, severity, message, flow?, nodeId?, path?, trigger? },
sorted from most to least severe.
The timeout checks (
invalid-timeout, missing-timeout,
wait-never-expires) also cover .form() steps. missing-timeout fires on
most small bots by design; use minSeverity: 'warning' for a quieter report.
Lower-level helpers
describeFlows(source, options)andlintFlows(source, options)accept aBot, aFlowInventoryor an array of flows.bot.flowInventory()returns the snapshot they work on (registrations, routes, the default timeout and whether the store is durable) for your own tooling.MemoryStore#durableistruewhen it has afile.describeTrigger(trigger)returns{ label, patterns, match, scope, predicate }.