Human-in-the-Loop Overview

Human-in-the-Loop Overview

Human-in-the-Loop (HITL) is a first-class feature in LeafMesh. Human agents are full mesh nodes — they have yields, can_call rules, and condition evaluation — but route execution to a person instead of a model.

How It Works

agents: human_reviewer: name: "human_reviewer" agent_type: "human" is_human_powered: true human_interface: "api" human_timeout_seconds: 300 communication_type: "dual" webhook_config: connection: "review-dashboard" # Outbound webhook record (Infrastructure → Add custom) outbound_timeout: 30 inbound_endpoint: "/webhook/process_request" max_retries: 3 retry_delay: 5 yields: decision: "string" notes: "string" can_call: - agent: "executor" condition: "decision == 'approved'" - agent: "rejection_handler" condition: "decision == 'rejected'"

When the mesh routes to a human agent:

  1. LeafMesh sends an outbound webhook to the address on the seat's webhook record (named by connection:)
  2. The payload includes the upstream agent's output, session_id, conversation history, and timeout
  3. The flow pauses, waiting for the human's response
  4. The human reviews the data and responds via POST /webhook/{entry_point} with the session_id
  5. LeafMesh verifies the HMAC signature, matches the pending session, and resumes the flow
  6. can_call conditions are evaluated against the human's response
  7. Downstream agents fire based on the human's decision

Complete Flow

mesh_call("entry_point", data)
    │
    ▼
LLM Agent (greeter, processor, etc.)
    │ can_call → human agent
    ▼
Human Agent triggered
    │
    ├── 1. Outbound webhook → your system (Slack, dashboard, email)
    │      Payload: session_id, input_data, conversation_history, timeout
    │
    ├── 2. Flow PAUSES, awaiting the human response
    │      (mesh_call returns greeter's result immediately)
    │
    ├── 3. Human reviews data in your system
    │
    ├── 4. Human responds: POST /webhook/{entry_point}
    │      Header: X-LeafMesh-Signature: sha256=<HMAC>
    │      Body: {"session_id": "...", "decision": "approved", "message": "..."}
    │
    ├── 5. LeafMesh verifies signature, finds the pending session
    │      Status: "resumed" (not "accepted")
    │
    ├── 6. can_call evaluated against response
    │      decision == 'approved' → executor agent
    │      decision == 'rejected' → rejection_handler
    │
    └── 7. Downstream chain continues automatically

HMAC Webhook Signing

All webhook traffic (inbound and outbound) is HMAC-SHA256 signed. The signing secret is LEAFMESH_WEBHOOK_SECRET in the mesh's .env (from 2.4.507 the mesh never derives one; without it, signed webhooks answer 503). Load the same value into your code from an environment variable:

import os secret = os.environ["LEAFMESH_WEBHOOK_SECRET"]

Sign inbound requests with the X-LeafMesh-Signature header:

X-LeafMesh-Signature: sha256=<HMAC-SHA256 hex digest of request body>

HITL Event Lifecycle

Events published during human agent execution:

EventWhen
HUMAN_INPUT_REQUESTEDOutbound webhook sent, waiting for human
HUMAN_INPUT_RECEIVEDHuman responds via inbound webhook
HUMAN_INPUT_TIMEOUTHuman doesn't respond within timeout
WORKFLOW_PAUSEDFlow paused waiting for human input
WORKFLOW_RESUMEDFlow resumed after human responds
HUMAN_ESCALATIONManager escalates to human intervention

The Manager subscribes to all HITL events. On timeout the default is to escalate/error — a non-responding human is never treated as an assumed answer. Automatic fallback to a fixed response is available only when explicitly opted in with fallback_on_timeout: true (see Workflows → Timeout Handling).

Timeouts survive restarts

Every request's answer deadline is durable. If the mesh restarts while a request is pending, the request still resolves once its window closes: the inbox entry moves from pending to resolved (reason request_timeout), the live inbox updates, and an audit entry lands in the thread. Two guarantees ride along:

  • Notifications are exempt — they carry no deadline and wait for acknowledgment indefinitely, by design.
  • An answerable request is never closed early — as long as its response window is genuinely open, it stays pending.

Key Properties

  • Full mesh node: Human agents participate in can_call chains, fan-in/fan-out, and condition routing identically to LLM agents
  • YAML-only integration: Add human review by adding a human agent to config — no code changes needed
  • Webhook-native: Outbound notification + inbound response via standard HTTP webhooks
  • HMAC-signed: All webhook traffic is cryptographically signed
  • Configurable timeout: Default 300 seconds, configurable per agent
  • Two communication modes: "dual" (async, non-blocking) or "chain" (blocking, waits for response)

Next Steps


LeafMesh — Human agents as first-class mesh nodes

Last updated: 11/10/2026