Skip to main content

bot.describe(): Mermaid diagram or JSON graph

What it draws:
  • One subgraph per DSL flow. The entry node (▶) lists every trigger that starts it (bot.use, bot.when(trigger, flow), a bot.conversation trigger). With bot.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, ✓schema when it validates with a schema), do (with the function name if it has one: do: saveUser()), media (with its kind: media (document): ...), choose (a diamond; options are arrows labelled 1) Label, like the menu the user sees), form (its fields and state key), guard (guard: isAdmin(), with ✗→ target when 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) and end.
  • 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’s goto is an arrow to its target flow.
  • The flow’s .timeout() and .persistent() go in the subgraph title.
  • A goto to a flow that does not exist is drawn as a missing: name node.
  • Steps after an unconditional goto have 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

Each diagnostic is { 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) and lintFlows(source, options) accept a Bot, a FlowInventory or 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#durable is true when it has a file.
  • describeTrigger(trigger) returns { label, patterns, match, scope, predicate }.

Next steps