Start runs from your app
Your app starts runs, follows them and reads their answers through the SDK's client, which calls Kindgi over HTTP. This page shows it in TypeScript and in Python. For Java, see Call Kindgi from a Java app.
Before you start, add Kindgi to your app: TypeScript or Node or Python.
Your app calls Kindgi over HTTP, through the SDK's client.
Connect your app to the runtime
Section titled “Connect your app to the runtime”In development, kindgi dev is enough: it writes the API's URL and a token
to .kindgirc.json, and the client finds them there, with a one-time warning
to set them. For production, and to silence the warning, give them to your
app as KINDGI_API_URL and KINDGI_API_TOKEN in your env file (.env /
.env.local). kindgi dev prints them (API and Token in its banner):
KINDGI_API_URL=http://127.0.0.1:4000KINDGI_API_TOKEN=kgi_bt_…The client looks for them when it's first used, not when you create it. So
const kindgi = createClient() at the top of a module is safe in a
production build that runs without them: next build, for one, loads every
route's module. If they're still missing when your app first uses the client,
that use throws an error that names what to set. Python's Kindgi() and
AsyncKindgi() do the same, so a module-scope kindgi = Kindgi() doesn't
break a build step that imports your app, such as Django's collectstatic.
The first request raises ValueError, naming what to set.
The banner's first line, Console, is the console's address
(http://127.0.0.1:4000/console/; kindgi console opens it). Sign in there
with Sign in as seeded user, or with the same token.
The token stays the same when you restart kindgi dev. kindgi dev --reset
starts the project over, dropping its database
(after asking), with a new
token: copy the new token after it (the client warns when the token in your
env file no longer matches).
In production they're your deployment's URL and API token. To pass them
yourself instead: createClient({ apiUrl, auth: { kind: 'apiToken', token } }),
or Kindgi(url, token=…) in Python.
In a CommonJS app
Section titled “In a CommonJS app”An app that isn't "type": "module", or that compiles to CommonJS, loads
the client with require():
const { createClient } = require('@kindgi/sdk/client');- Node 22.12 or later. The SDK is ES modules, and Node's
require()loads ES modules from 22.12 on. - TypeScript that compiles to CommonJS: TypeScript 5.8 or later, with
"module": "nodenext". In an app a bundler builds,"moduleResolution": "bundler"works too. With"moduleResolution": "node10"(or"node"), TypeScript doesn't find the SDK's types.
Pack code (kindgi/) is ES modules in every app; init sets that up.
Run an agent and read its answer
Section titled “Run an agent and read its answer”Ask your coding agent: "I want our app to run the triage agent on a support request and use its answer." For reference, the code looks like this:
import { createClient } from '@kindgi/sdk/client';
export const kindgi = createClient(); // KINDGI_API_URL, KINDGI_API_TOKEN, or the running kindgi devimport { KindgiApiError } from '@kindgi/sdk/client';
import { kindgi } from '@/lib/kindgi';
type Triage = { priority: 'low' | 'normal' | 'urgent'; summary: string };
export async function GET(_request: Request, { params }: { params: Promise<{ id: string }> }) { const { id } = await params; try { const run = await kindgi.runs.start({ agent: 'acme-support.triage', input: { userMessage: `Triage ${id}` }, }); const { output } = run.output as { output: Triage }; // the agent's typed answer return Response.json(output); } catch (error) { if (error instanceof KindgiApiError) { const code = error.error.code === 'server' ? error.error.serverCode : error.error.code; return Response.json({ error: code, message: error.error.message }, { status: 502 }); } throw error; }}- An agent's input is
{ userMessage }.runs.startwaits for the answer. run.output.outputis the typed answer of an agent with anoutput;run.output.response.contentis the answer as text. A flow'srun.outputis the flow's own output.- When the turn fails, or the API refuses the call,
runs.startthrows aKindgiApiError.error.error.codesays what kind of failure it is (not-found,auth,network, …); for a failure on the server (server),error.error.serverCodeis the server's own code, such asoutput-schema-violation.
In Python:
from kindgi.client import Kindgi, KindgiApiError
kindgi = Kindgi() # KINDGI_API_URL, KINDGI_API_TOKEN, or the running kindgi devtry: run = kindgi.runs.start(agent="acme-support.triage", input={"userMessage": "Triage REQ-1002"}) if run.output is None: # a run that didn't complete has no output raise SystemExit(f"Run {run.id} ended {run.status}: {run.failure_message}") triage = run.output["output"]except KindgiApiError as error: print(error.code, error.server_code, error.message)Follow a run as it runs
Section titled “Follow a run as it runs”Start the run with wait: false and the call returns as soon as the run
exists. Its events then arrive as they happen, through to its last one. Ask
your coding agent: "I want our app to stream the triage run's progress
live." For reference, the route looks like this:
import { kindgi } from '@/lib/kindgi';
export async function GET(_request: Request, { params }: { params: Promise<{ id: string }> }) { const { id } = await params; const run = await kindgi.runs.start({ agent: 'acme-support.triage', input: { userMessage: `Triage ${id}` }, options: { wait: false }, // returns as soon as the run exists });
const encoder = new TextEncoder(); const body = new ReadableStream({ async start(controller) { for await (const event of kindgi.runs.follow(run.id)) { controller.enqueue(encoder.encode(`data: ${JSON.stringify(event)}\n\n`)); } controller.close(); }, }); return new Response(body, { headers: { 'content-type': 'text/event-stream' } });}Each event has a kind (run.started, run.step-started,
run.step-completed, …, run.completed) and a payload; the
run.completed event's payload.output is the run's output. In Python,
kindgi.runs.follow(run.id) is an iterator of the same events, through to
the run's end.
A browser can also follow a run directly, with a short-lived read-only token, without your API token: see Follow a run from the browser. To be told when a run ends instead, have Kindgi send your app a signed webhook: see Get a webhook when a run finishes.
Keep what a run did
Section titled “Keep what a run did”Store the run's id on your own row (a kindgi_run_id column), and read its
status, output, steps and sources through the API when your app shows them.
Never from Kindgi's database, and never by sending users to Kindgi's
console: see Show runs in your app.
- Follow a run: every way to watch one.
- Show runs in your app.
- Retry a start safely.