Kitaru
Guides

Wait, Input, and Resume

Suspend a flow for external input and continue the same execution

kitaru.wait(...) is the durable suspension primitive for human-in-the-loop and external-input workflows.

When your flow reaches wait(...), what happens next depends on the environment:

  • Local interactive runs (terminal with stdin/stdout): the runtime prompts for input directly in the same terminal and the flow continues in-process.
  • Non-interactive runs (remote orchestrators, CI, piped output, MCP): the execution moves to waiting status and input must be supplied later via the client, CLI, or MCP.

Basic pattern

from kitaru import flow
import kitaru

@flow
def publish_flow(topic: str) -> str:
    approved = kitaru.wait(
        schema=bool,
        name="approve_publish",
        question=f"Approve publishing {topic}?",
        metadata={"topic": topic},
    )
    if not approved:
        return f"REJECTED: {topic}"
    return f"PUBLISHED: {topic}"

Timeout behavior

By default, kitaru.wait(...) gives the runner up to 600 seconds to receive inline input before pausing the execution:

approved = kitaru.wait(
    schema=bool,
    name="approve_publish",
    question="Approve publishing?",
    timeout=300,  # runner waits up to 300s for inline resolution
)

timeout controls how long the runner keeps polling — it is not an expiration on the wait record itself. If the timeout elapses without input, the execution moves to waiting status and can still be resolved externally at any time.

Resolve input externally (non-interactive runs)

When the flow is running in a non-interactive context (or after the runner has timed out and paused), resolve the pending wait from Python or the CLI.

From Python

client = kitaru.KitaruClient()
execution = client.executions.input(
    exec_id,
    wait="approve_publish",
    value=True,
)

If the execution does not continue automatically after input (e.g. the original runner already exited), call resume(...):

execution = client.executions.resume(exec_id)

To abort a wait instead of continuing:

execution = client.executions.abort_wait(exec_id, wait="approve_publish")

From CLI

kitaru executions input <exec_id> --value true

The CLI auto-detects the single pending wait. For interactive review (with JSON schema display, continue/abort choices, and multi-execution sweep):

kitaru executions input <exec_id> --interactive
kitaru executions input --interactive  # sweep all waiting executions

To abort a wait instead of continuing:

kitaru executions input <exec_id> --abort

Resume is only needed when the execution did not continue automatically:

kitaru executions resume <exec_id>

Validation behavior

Input is validated against the wait schema:

  • invalid input raises kitaru.KitaruWaitValidationError
  • execution stays in waiting until valid input is supplied

Example in this repository

uv sync --extra local
uv run examples/execution_management/wait_and_resume.py
  1. Run the command above — it starts the flow and blocks.
  2. If you are in an interactive terminal, the runtime prompts for input directly. Type your answer and the flow continues.
  3. If the run is non-interactive (or you want to resolve from elsewhere), the script prints fallback kitaru executions input ... and kitaru executions resume ... commands you can run in a second terminal.

Automated CI coverage for the same flow lives in tests/test_phase15_wait_example.py.

For the broader catalog, see Examples.

On this page