Getting started

Quickstart

From zero to an agent whose tool calls flow through Klent in five minutes.

This guide builds the minimum integration that gives you the three things Klent exists for: a logged execution, a policy-evaluated action, and a timeline you can inspect.

By the end you will have:

  1. Started an execution — a session of agent activity.
  2. Evaluated an action — a tool call — against your policies.
  3. Logged the outcome as an event on the execution timeline.

You should have completed Install first.

Step 1 — Start an execution

An execution is the parent container for everything a single agent run does. Create one before any tool call.

import { KlentClient } from '@klent/sdk';

const klent = new KlentClient({ apiKey: process.env.KLENT_API_KEY! });

const execution = await klent.startExecution({
  agent_id: 'support-agent',
  metadata: { user_id: 'u_123', tenant: 'acme' },
});
from klent_sdk import KlentClient

klent = KlentClient(api_key=os.environ["KLENT_API_KEY"])

execution = klent.start_execution({
    "agent_id": "support-agent",
    "metadata": {"user_id": "u_123", "tenant": "acme"},
})

The returned execution.id is how you tie every subsequent event and action back to this particular run. Pass it through your call stack — it is the correlation key.

Step 2 — Evaluate before you act

When your agent decides to call a tool, do not execute it yet. Ask Klent first:

const decision = await klent.evaluateAction({
  execution_id: execution.id,
  tool: 'send_email',
  input: { to: user.email, subject: 'Refund issued', body: '...' },
});

if (decision.decision === 'deny') {
  // Surface the reason back to the LLM or fail the turn.
  throw new Error(`Blocked by policy: ${decision.reason}`);
}

if (decision.decision === 'modify') {
  // Apply the suggested modifications to the input before executing.
  // (Modifications are described in docs/concepts/policy-engine.)
}

// decision.decision === 'allow' — safe to proceed
await sendEmail(input);
decision = klent.evaluate_action({
    "execution_id": execution["id"],
    "tool": "send_email",
    "input": {"to": user.email, "subject": "Refund issued", "body": "..."},
})

if decision["decision"] == "deny":
    raise RuntimeError(f"Blocked by policy: {decision['reason']}")

# decision['decision'] == 'allow' — safe to proceed
send_email(input)

evaluateAction is synchronous and returns in a few milliseconds. It also writes a decision or action_blocked event to the execution timeline automatically — you do not have to log it yourself.

Step 3 — Log the outcome

After the tool runs (or fails), record what actually happened:

klent.logEvent({
  execution_id: execution.id,
  type: 'action_executed',
  payload: { tool: 'send_email', to: user.email },
});
klent.log_event({
    "execution_id": execution["id"],
    "type": "action_executed",
    "payload": {"tool": "send_email", "to": user.email},
})

logEvent is non-blocking. Events are buffered and flushed in batches, and on process exit the SDK flushes once more. You do not need to await it.

If the tool throws, log it as an error:

klent.logEvent({
  execution_id: execution.id,
  type: 'error',
  payload: { tool: 'send_email', message: err.message, stack: err.stack },
});

Step 4 — Check the dashboard

Open the execution in the dashboard (/executions/<execution_id>) and you should see the timeline:

  • decision (from evaluateAction)
  • action_executed (from logEvent)

That is the full observability loop.

Next