build-wizard-flow

star 247

Creates multi-step wizard flows with validation and state persistence using @WizardHandler and WizardStep. Use when building forms, questionnaires, or multi-step conversations that need typed state and validation.

vendelieu By vendelieu schedule Updated 2/15/2026

name: build-wizard-flow description: Creates multi-step wizard flows with validation and state persistence using @WizardHandler and WizardStep. Use when building forms, questionnaires, or multi-step conversations that need typed state and validation.

Build Wizard Flow

Quick Start

Annotate an object/class with @WizardHandler. Define nested steps extending WizardStep. KSP generates the WizardActivity; no manual Activity class needed.

import eu.vendeli.tgbot.types.component.MessageUpdate

@WizardHandler(trigger = ["/start"])
object RegistrationWizard {
    object NameStep : WizardStep(isInitial = true) {
        override suspend fun onEntry(ctx: WizardContext) {
            message("What's your name?").send(ctx.user, ctx.bot)
        }
        override suspend fun validate(ctx: WizardContext): Transition {
            val text = (ctx.update as? MessageUpdate)?.message?.text ?: return Transition.Retry()
            return if (text.isNotBlank()) Transition.Next else Transition.Retry("Invalid name")
        }
        override suspend fun store(ctx: WizardContext): String? =
            (ctx.update as? MessageUpdate)?.message?.text
    }

    object AgeStep : WizardStep() {
        override suspend fun onEntry(ctx: WizardContext) {
            message("How old are you?").send(ctx.user, ctx.bot)
        }
        override suspend fun validate(ctx: WizardContext): Transition {
            val age = (ctx.update as? MessageUpdate)?.message?.text?.toIntOrNull()
            return if (age != null && age in 1..150) Transition.Next else Transition.Retry()
        }
        override suspend fun store(ctx: WizardContext): Int? =
            (ctx.update as? MessageUpdate)?.message?.text?.toIntOrNull()
    }
}

WizardStep Lifecycle

  • onEntry(ctx) — Called when entering the step. Send prompts, set keyboards.
  • validate(ctx) — Return Transition based on input.
  • store(ctx) — Return value to persist (or null). Type must match a state manager.
  • onRetry(ctx, reason) — Called when validation fails (optional).

Transitions

Transition Effect
Transition.Next Move to next step in sequence
Transition.JumpTo(Step::class) Jump to specific step
Transition.Retry() or Transition.Retry("reason") Stay on step, call onRetry
Transition.Finish End wizard

State Managers

Default: MapStringStateManager, MapIntStateManager, MapLongStateManager. KSP matches store() return type to the manager.

Override per step:

@WizardHandler.StateManager(CustomStateManager::class)
object CustomStep : WizardStep { ... }

WizardContext

  • ctx.user, ctx.update, ctx.bot
  • ctx.getState(Step::class), ctx.setState(Step::class, value), ctx.delState(Step::class) — type-safe accessors generated by KSP for each step

Trigger and Scope

  • trigger = ["/start", "/register"] — commands that start the wizard
  • scope = [UpdateType.MESSAGE] — default; use UpdateType.CALLBACK_QUERY for button-triggered wizards

Related Skills

  • add-wizard-handler — Configure @WizardHandler (trigger, scope, state managers)
  • add-wizard-step — Implement WizardStep (onEntry, validate, store, transitions)

Reference

Install via CLI
npx skills add https://github.com/vendelieu/telegram-bot --skill build-wizard-flow
Repository Details
star Stars 247
call_split Forks 17
navigation Branch main
article Path SKILL.md
More from Creator