Skip to content

Kortex — AI Integration

Kortex is the platform's built-in AI assistant. Forge apps can register tools and page context so the assistant understands what your app can do and where the user currently is. With a few lines of code, the user can talk to the assistant and it will call back into your app to read data, trigger actions, and navigate on the user's behalf.


Setup

Install the @ptkl/components package and import from the forge entry point:

npm install @ptkl/components
import { registerTool, registerContext, showHelper } from '@ptkl/components/forge'

For React apps, hooks are also available:

import { useKortexTool, useKortexContext, useKortexHelper } from '@ptkl/components/forge'

Getting Started

To make your app AI-ready, you only need two things:

  1. Register context — tell the assistant what the user is looking at.
  2. Register tools — tell the assistant what your app can do.
import { registerTool, registerContext } from '@ptkl/components/forge'
import { Platform } from '@ptkl/sdk'

const sdk = new Platform()

// 1. Describe the current page
registerContext(
  'Order #1234',
  'Viewing order details. Status: processing. Customer: John Doe.'
)

// 2. Give the assistant a tool it can call
registerTool(
  'get_order_status',
  'Returns the current status of an order by UUID.',
  {
    type: 'object',
    properties: {
      uuid: { type: 'string', description: 'Order UUID.' }
    },
    required: ['uuid']
  },
  async (args) => {
    const order = await sdk.component('orders').get(args.uuid)
    return { status: order.status, updated_at: order.updated_at }
  }
)

Now a user can ask "What's the status of this order?" and the assistant will call your tool and answer.


Registering Tools

registerTool

import { registerTool } from '@ptkl/components/forge'

registerTool(name, description, parameters, execute, policy?)
Parameter Type Required Description
name string Unique tool identifier (e.g. 'get_order_details').
description string What the tool does — the assistant reads this to decide when to use it.
parameters object JSON Schema describing the tool's arguments.
execute function The function that runs when the assistant calls the tool. Receives parsed arguments, returns the result. Can be sync or async.
policy object Override the default confirmation behavior. See Tool Policies.

unregisterTool

import { unregisterTool } from '@ptkl/components/forge'

unregisterTool('tool_name')

Remove a tool when it's no longer relevant — for example, when the user navigates away from the page.

Registering a tool with the same name replaces the old one

You don't need to call unregisterTool before re-registering. Kortex handles deduplication automatically.


Registering Context

registerContext

import { registerContext } from '@ptkl/components/forge'

registerContext(label, description, icon?)
Parameter Type Required Description
label string Short label for the current page (e.g. "Order #1234").
description string Describe what the user is currently seeing or doing.
icon string Icon identifier for visual representation.

The description is the most important part — it gives the assistant situational awareness. Be specific:

// ❌ Too vague
registerContext('Orders', 'The orders page.')

// ✅ Specific and useful
registerContext(
  'Orders',
  'Browsing the orders list. Filters: status=processing, date=last 7 days. 24 results shown.'
)

unregisterContext

import { unregisterContext } from '@ptkl/components/forge'

unregisterContext()

Clear the context when the user leaves a page.


Tool Policies

Policies control whether the user sees a confirmation prompt before a tool executes. By default, Kortex infers the policy from the tool name:

Name your tool with… What happens
get_*, list_*, find_*, search_* Runs automatically — no confirmation needed.
set_*, save_*, add_*, update_* Asks the user to confirm before running.
create_*, publish_*, delete_*, remove_* Asks to confirm — treated as a higher-risk action.

Name your tools with clear prefixes

A tool named get_order will run without asking. A tool named delete_order will always ask for confirmation. Choose prefixes that match the action's risk level.

Overriding the default policy

If the automatic inference doesn't fit, pass a policy object as the last parameter:

registerTool(
  'export_report',
  'Export the current report as PDF.',
  { type: 'object', properties: {} },
  () => exportToPDF(),
  { risk: 'low', requiresConfirmation: false }
)
Policy field Type Description
risk 'low' \| 'medium' \| 'high' Risk level of the action.
requiresConfirmation boolean Whether the user must approve before the tool runs.
category string Category label (e.g. 'read', 'write', 'destructive').
fullAccessAuto boolean Auto-execute when the user has granted full access.

Helper Visibility

Signal to the user that AI help is available on the current page by activating the Kortex button glow:

import { showHelper, hideHelper } from '@ptkl/components/forge'

showHelper()   // show the glow indicator
hideHelper()   // hide the glow indicator

React Hooks

For React apps, hooks handle registration and cleanup automatically:

useKortexTool

Registers a tool on mount, unregisters on unmount. Re-registers if the name, description, or parameters change.

import { useKortexTool } from '@ptkl/components/forge'

function OrderDetail({ orderId }) {
  useKortexTool(
    'get_order_status',
    'Returns the current status of this order.',
    {
      type: 'object',
      properties: {
        uuid: { type: 'string', description: 'Order UUID.' }
      },
      required: ['uuid']
    },
    async (args) => {
      const order = await sdk.component('orders').get(args.uuid)
      return { status: order.status }
    }
  )

  return <div>...</div>
}

useKortexContext

Sets the page context on mount, clears on unmount. Updates when label or description change.

import { useKortexContext } from '@ptkl/components/forge'

function OrderDetail({ order }) {
  useKortexContext(
    `Order #${order.number}`,
    `Viewing order ${order.number}. Status: ${order.status}. Customer: ${order.customer_name}.`
  )

  return <div>...</div>
}

useKortexHelper

Shows the helper glow on mount, hides on unmount.

import { useKortexHelper } from '@ptkl/components/forge'

function ProductCatalog() {
  useKortexHelper()
  return <div>...</div>
}

useIsKortexAvailable

Check whether Kortex is available in the current environment.

import { useIsKortexAvailable } from '@ptkl/components/forge'

function MyApp() {
  const kortexAvailable = useIsKortexAvailable()

  return (
    <div>
      {kortexAvailable && <span>AI assistant is available</span>}
    </div>
  )
}

Examples

Read-only tool — no parameters

registerTool(
  'get_current_page',
  'Returns the current page URL the user is viewing.',
  { type: 'object', properties: {} },
  () => ({
    href: window.location.href,
    path: window.location.pathname
  })
)

Tool with parameters

registerTool(
  'search_orders',
  'Search orders by status and date range.',
  {
    type: 'object',
    properties: {
      status: {
        type: 'string',
        enum: ['pending', 'processing', 'shipped', 'delivered'],
        description: 'Order status to filter by.'
      },
      from_date: {
        type: 'string',
        description: 'Start date in ISO 8601 format.'
      }
    },
    required: ['status']
  },
  async (args) => {
    const orders = await fetchOrders({ status: args.status, from: args.from_date })
    return { count: orders.length, orders }
  }
)

Write tool — creates a record

registerTool(
  'create_invoice',
  'Create a new invoice for a customer.',
  {
    type: 'object',
    properties: {
      customer_uuid: { type: 'string', description: 'Customer UUID.' },
      items: {
        type: 'array',
        items: {
          type: 'object',
          properties: {
            product_uuid: { type: 'string' },
            quantity: { type: 'number' }
          }
        },
        description: 'Line items for the invoice.'
      }
    },
    required: ['customer_uuid', 'items']
  },
  async (args) => {
    const invoice = await sdk.component('invoices').create({
      customer_uuid: args.customer_uuid,
      items: args.items
    })
    return { uuid: invoice.uuid, total: invoice.total }
  }
)

Best Practices

  • Write clear descriptions. The assistant chooses which tool to call based on the description. Be specific about what it does, what it returns, and when to use it.
  • Keep tools focused. One tool, one action. Prefer get_order + update_order_status over a single manage_order.
  • Return structured data. Return objects and arrays — the assistant presents structured data better than plain strings.
  • Register and unregister with the page lifecycle. Only expose tools that are relevant to the current page. Clean up on unmount.
  • Throw descriptive errors. If a tool fails, the error message goes to the assistant. Make it helpful: "Order not found: abc-123" is better than "Not found".