Studio previewSelf-host Studio locally.Run it

Connect Your Kortyx Project

Updated 7 days ago • September 16, 2026

Connect Studio at the agent boundary. One telemetry adapter can observe the sessions, runs, workflows, nodes, model calls, and interrupts produced by that agent.

Prerequisite: Start a local installation with Run Studio Locally, or obtain the telemetry API URL and Project-scoped write key from the operator of your remote deployment.

Install the adapter

pnpm add @kortyx/telemetry

Configure the server environment

.env.local
KORTYX_TELEMETRY_API_URL=http://localhost:6400 KORTYX_TELEMETRY_API_KEY=ktyx_live_... KORTYX_TELEMETRY_ENVIRONMENT=development KORTYX_TELEMETRY_SERVICE_NAME=my-agent
VariableMeaning
KORTYX_TELEMETRY_API_URLReachable base URL of the telemetry API
KORTYX_TELEMETRY_API_KEYProject-scoped telemetry:write key
KORTYX_TELEMETRY_ENVIRONMENTInformational label such as development or production
KORTYX_TELEMETRY_SERVICE_NAMEStable name for this SDK application or agent service

Do not prefix these variables with NEXT_PUBLIC_, VITE_, or another mechanism that exposes them to client code.

Attach telemetry to the agent

src/lib/agent.ts
import { createAgent } from "kortyx"; import { createKortyxTelemetryAdapter } from "@kortyx/telemetry"; import { workflows } from "./workflows"; const telemetry = createKortyxTelemetryAdapter({ endpoint: process.env.KORTYX_TELEMETRY_API_URL!, apiKey: process.env.KORTYX_TELEMETRY_API_KEY!, environment: process.env.KORTYX_TELEMETRY_ENVIRONMENT ?? "development", service: { name: process.env.KORTYX_TELEMETRY_SERVICE_NAME ?? "my-agent", }, }); export const agent = createAgent({ workflows, telemetry });

Keep the service name stable across deploys. Use the environment field as an informative label; it does not create a separate security or storage boundary.

Collect response feedback

Kortyx assistant messages expose runId through @kortyx/react. Use the run reference to connect a response rating to Studio. Send the rating to your own authenticated backend first: derive the actor from the signed-in user and verify that the response/run belongs to that user. Do not accept an arbitrary browser-supplied run ID without an ownership check or signed feedback token.

After those checks, forward a server-to-server request:

const response = await fetch( `${process.env.KORTYX_TELEMETRY_API_URL}/v1/telemetry/scores`, { method: "POST", headers: { authorization: `Bearer ${process.env.KORTYX_TELEMETRY_API_KEY}`, "content-type": "application/json", }, body: JSON.stringify({ runId: verifiedResponse.runId, actorId: authenticatedUser.id, value: liked ? 1 : 0, reasons: selectedReasons, comment: optionalComment, }), }, ); if (!response.ok) throw new Error("Feedback could not be saved.");

verifiedResponse, authenticatedUser, liked, selectedReasons, and optionalComment represent your application-owned validated values. Reasons are optional: incorrect, irrelevant, incomplete, unsafe, or other. Comments are optional and capped at 4000 characters. Do not assign a negative reason automatically if the user has not selected one.

One vote is stored per actor/run. Changing the vote updates its existing score; send DELETE to the same endpoint with { runId, actorId } to clear it. The run must already exist in Studio, so flush/retry pending telemetry before treating a 404 as permanent. No credentials are exposed to the chat browser.

Studio surfaces ratings in Runs → Feedback, its feedback filter, and session activity. A negative rating does not mark execution as failed. Human correctness reviews appear separately and require a Studio key with studio:write in addition to studio:read. Shared-key self-hosted reviews use the Studio key as reviewer identity. These native Studio scores are independent of the optional Langfuse integration; forwarding to Langfuse remains application-owned.

Publish the declared workflow catalog

Good to know: Make this a CI/CD step, not a one-time setup command. Publish topology for each application release, ideally before that version serves traffic. Run the CLI where the telemetry API is reachable and inject the same server-only telemetry variables as the application. If the API is private, use a network-connected runner or a one-off task/job inside the allowed network; an ordinary public CI runner does not gain access just because Studio is deployed. See the AWS ECS task pattern.

Publish deterministic topology from the module that exports your configured agent or workflows:

npx kortyx topology push --entry src/lib/agent.ts

Use --dry-run to inspect the projection without writing to Studio:

npx kortyx topology push --entry src/lib/agent.ts --dry-run

The published catalog appears under Workflows before traffic arrives. This does not create a run. Runs contains only real workflow executions emitted by your application. Keep runtime topology registration enabled as a best-effort fallback, but use topology push as the canonical deployment step.

For a release container, keep a small catalog module in the application repository that exports the same workflow definitions without starting the server or connecting to application persistence:

src/catalog.ts
export { workflows } from "./workflows.js";

Build and include it in the application artifact. If the compiled path is dist/catalog.js, run the installed CLI from the application directory:

./node_modules/.bin/kortyx topology push --entry dist/catalog.js

Use the exact application version being released, keep the service name and environment aligned with runtime telemetry, and check the command's exit code before marking publication successful. Topology publication targets the telemetry API, not the Studio browser interface. It is separate from deploying Studio or running its database bootstrap.

Choose what content Studio may store

Structural telemetry is useful without storing prompts or responses. Input and output content are excluded by default.

Enable only the content your application is permitted to export:

src/lib/agent.ts
const telemetry = createKortyxTelemetryAdapter({ endpoint: process.env.KORTYX_TELEMETRY_API_URL!, apiKey: process.env.KORTYX_TELEMETRY_API_KEY!, captureContent: { input: true, output: false, }, });
SettingData that may be included
input: trueUser/application inputs and submitted interrupt responses
output: trueModel/application outputs, interrupt questions, and static option labels
Both falseStructural lifecycle, timing, model identity, token usage, and status only

Option values and resume tokens are never sent as telemetry. Review retention, access, and regulatory requirements before enabling content capture in production.

Interrupt behavior in Studio

Studio observes interrupt lifecycle events; your application still presents the request and sends the resume response.

  • Pending interrupt state expires after 15 minutes by default.
  • Configure the application TTL with KORTYX_FRAMEWORK_TTL_MS, or with frameworkAdapter.ttlMs.
  • Studio derives Expired from the durable expiresAt timestamp.
  • A late response cannot resume the expired run, although application fallback may handle it as a new run.
  • A dynamic picker may correctly report zero embedded options because the client resolves choices from its own data source.

For runtime behavior and replay-safe side effects, read Interrupts and Resume.

Verify the connection

Open Workflows after the topology push, then trigger one agent request and open Runs in Studio. If nothing arrives, use this order:

  1. Confirm the application server has all four environment variables.
  2. Confirm it restarted after configuration changed.
  3. Confirm topology push used the entry module and service name for this app.
  4. Check the Studio stack with npx kortyx studio status.
  5. Inspect recent logs with npx kortyx studio logs --no-follow.
  6. Confirm the Studio time filter includes the event.

For remote deployments, also verify network reachability from the application server to the telemetry API and confirm the supplied key has telemetry:write scope.