Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.karta.sh/llms.txt

Use this file to discover all available pages before exploring further.

Two mechanisms let you observe and constrain a Karta app without touching the harness: hooks (react to lifecycle events) and policies (validate messages before they run).

Hooks

Register a handler for a lifecycle event with @app.on(...). Handlers receive a HookEvent carrying the session, message, and any event-specific payload.
app = Karta()

@app.on("message.completed")
async def log_response(event):
    print(f"Session {event.session.id}: {event.message.text}")

@app.on("agent.handoff")
async def track_handoff(event):
    print(f"Handoff: {event.payload['from']}{event.payload['to']}")

Available events

EventFires when
session.createdA new session is opened.
message.receivedAn inbound message is accepted, before the turn runs.
message.completedA turn finishes and the assistant message is ready.
agent.handoffA session’s current_agent changes.
Use hooks for logging, metrics, side effects (notify a channel on handoff), or enrichment — they observe the flow without owning it.

Policies

Policies validate messages against configurable rules before a turn runs — length limits, message counts, keyword gates.
app.policy("max_message_length", 4000)
A message that violates a policy is rejected before reaching the harness, so policy checks are cheap and deterministic — exactly the kind of guardrail you want in code rather than left to the model.
Hooks and policies run in the thin core of the data plane — they’re part of orchestration, not the harness. They don’t see or alter conversation history (the harness owns that); they gate and observe the turns that flow through Karta. See Architecture.