Skip to main content
Version: 1.0.0

Handler

A handler implements a tool in your application’s language: JavaScript with @touba/sdk or Python with touba_sdk.

StepJavaScriptPython
Installtouba sdk install javascripttouba sdk install python
Define the handlerdefineTooldefine_tool
Adapt business logicrun({ request, context })run(request, context)
Test and runJavaScript tutorialPython tutorial

The excerpts below illustrate the JavaScript API. For a complete file connected to your tool, select the project language and run touba prepare --mode write.

The handler is not the primary source of authority. The runtime verifies the contract before and after the call.

SDK Shape​

handler.mjs
import { defineTool } from "@touba/sdk";

await defineTool({
toolRef: "tool:module.name/ToolName",
inputSignature: [{ name: "request", type_ref: "type:module.name/Input" }],
outputType: "type:module.name/Output",
run: async ({ request, context }) => {
return await runHostCode(request, context);
},
});

toolRef identifies the expected tool. The business function receives request and context, while the SDK handles the protocol envelope.

Simple Case​

search_datasets.handler.mjs
import { defineTool } from "@touba/sdk";

await defineTool({
toolRef: "tool:examples.tool_simple/SearchDatasets",
inputSignature: [{ name: "request", type_ref: "type:examples.tool_simple/DatasetSearchRequest" }],
outputType: "type:examples.tool_simple/DatasetSearchResult",
requiredGrants: ["network"],
run: async ({ request }) => {
const result = await searchDatasets(request.query);

return {
title: result.title,
};
},
});

The handler performs the concrete call. The runtime remains responsible for verifying that the input matches takes and that the output matches gives.

Advanced Case​

summarize_with_context.handler.mjs
import { defineTool } from "@touba/sdk";

await defineTool({
toolRef: "tool:examples.tool_advanced/SummarizeWithContext",
inputSignature: [{ name: "request", type_ref: "type:examples.tool_advanced/SearchRequest" }],
outputType: "type:examples.tool_advanced/Summary",
requiredGrants: ["network", "secret_read", "memory_read"],
requiredSecretHandles: ["LLM_API_KEY"],
run: async ({ request, context }) => {
const apiKey = context.env.LLM_API_KEY;
const knowledge = await readProjectKnowledge(request.query);
const summary = await callLlm(apiKey, {
query: request.query,
context: knowledge,
});

return {
text: summary.text,
};
},
});

This case shows a handler that consumes a secret value injected by the runtime's minimal environment and calls a host backend.

The secret value must not be written to the output, trace, displayed prompt, or errors.

What a Handler Carries​

The handler keeps non-portable details outside the .tb file:

  • HTTP clients;
  • provider SDKs;
  • database access;
  • API-specific formats;
  • adapters for existing backends.

Touba keeps the contract in source and AIR; the handler keeps the real host-side effect.

Supply Chain​

A handler can be attached to a supply-chain lock. The lock verifies its path, digest, command, SDK protocol, and handler_package identity. With dependency artifact extensions, it can also verify handler package files and dependency artifacts declared under that identity.

This identity helps organize handlers without scanning the workspace. Registry publication, signatures, package installation, and vulnerability auditing are governed by separate distribution mechanisms.

Runtime Contract​

  • The handler remains host code to audit.
  • The SDK does not replace runtime checks.
  • A handler authorized by the runtime still needs normal host security review.
  • Dependency graph resolution, vulnerability auditing, and automatic handler package installation extend the published static registry.