Skip to main content
Version: 1.0.0

Tool Binding, Handler, and Manifest

This guide explains how a Touba tool executes real code without putting that code in the .tb file.

Overview​

Structure
source .tb
declares a tool
|
v
AIR
carries requirements
|
v
runtime
verifies the manifest
|
v
handler
executes the real effect
|
v
trace
observes authorization, refusal, or success

Declare the Tool​

Shape:

source.tb
tool Name
takes input as InputType
gives OutputType
requires capability

Example:

source.tb
tool SearchDatasets
takes request as DatasetSearchRequest
gives DatasetSearchResult
requires network

This declaration does not grant network access. It says that the tool requires the network capability.

Tool capabilities​

V1 has a closed list: network, filesystem_read, filesystem_write, process, external_api, secret_read, human_approval, memory_read and memory_write. Other names produce UnknownToolCapability.

process covers host process operations, such as invoking Docker. Separate ReadLogs and RestartService into distinct tools so uses can allow one without the other. Grants are admission checks, not an OS sandbox. The human_approval capability alone creates no pause: put human.approve before the protected effect.

Generate the Manifest​

Shape:

Terminal
touba compile program.tb --out program.air.json
touba manifest generate program.air.json --out touba.manifest.json

In a Touba project, the recommended workflow is:

Terminal
touba prepare --mode plan
touba prepare --mode write
touba prepare --mode check

prepare produces or verifies the project manifest and handler stubs from AIR. The commands touba compile, touba manifest generate, and touba handler stub remain useful for understanding each transformation separately.

Example:

Terminal
touba compile search.tb --out search.air.json
touba manifest generate search.air.json --out touba.manifest.json

The manifest is a reviewable template. It connects a tool to a handler and declares granted capabilities, secrets, and limits.

Create a Handler​

Shape:

Terminal
touba handler stub program.air.json \
--tool-ref tool:module.name/ToolName \
--handler-root handlers

Example:

Terminal
touba handler stub search.air.json \
--tool-ref tool:examples.search/SearchDatasets \
--handler-root handlers

The generated file is a skeleton. The developer adds business code to it.

Write the Handler with the SDK​

Shape:

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

Example:

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

await defineTool({
toolRef: "tool:examples.search/SearchDatasets",
inputSignature: [{ name: "request", type_ref: "type:examples.search/SearchRequest" }],
outputType: "type:examples.search/SearchResult",
requiredGrants: ["network"],
run: async ({ request }) => {
return await searchDatasets(request);
},
});

The SDK handles the process protocol on the handler side. The runtime remains the primary authority for grants, secrets, scopes, limits, and payloads.

Run with an Explicit Manifest​

Shape:

Terminal
touba run program.air.json \
--manifest touba.manifest.json \
--inputs-json '{"input":{"field":"value"}}' \
--trace-out trace.json

Example:

Terminal
touba run search.air.json \
--manifest touba.manifest.json \
--inputs-json '{"request":{"query":"parks"}}' \
--trace-out trace.json

The runtime refuses before the handler if the manifest does not satisfy the AIR contract. By default, standard output displays show messages. Use --output result to display the returned value, or --output trace to write the JSON trace to standard output.

Even if the manifest was generated by touba prepare, it must be supplied explicitly to the runtime with --manifest.

Verify the Handler Supply Chain​

For a strict run, add a supply-chain lock coherent with AIR, manifest, handler, SDK, declared handler_package identity, handler package files, and declared dependency artifacts:

Terminal
touba run search.air.json \
--manifest touba.manifest.json \
--supply-chain-lock touba.lock.json \
--require-supply-chain-lock \
--inputs-json '{"request":{"query":"parks"}}'

The lock grants no runtime capability. It refuses drift before handler launch.

Observable Refusals​

The runtime can refuse when:

  • no binding exists for the tool;
  • the required grant is missing;
  • a required secret is missing;
  • the input payload does not match the signature;
  • the output payload does not match gives;
  • the handler exceeds its timeout;
  • the payload exceeds the declared limit.

Local handler diagnostics​

Unhandled exceptions retain a bounded public diagnostic, without arbitrary messages or stacks. To locate an exception in a prepared development project:

Terminal
touba run --project . --profile dev --handler-diagnostics diagnostic-local.jsonl

Add your program's required inputs and providers. The destination must be new. On macOS/Linux, it is exclusively created with mode 0600, without overwriting an existing file or following a final symlink. Records contain runtime failure codes, run/call identifiers, exception classes and, with the SDK, a line and column within a handler file argument (handler_arg_index). Calls into a different file may not yield a position.

No exception message, raw stack, stderr, payload or secret value is recorded. Limits are 4 KiB per private response, 128 events and 64 KiB per file. A warning reports incomplete diagnostics; malformed private data is discarded. This is not evidence of business effects, and is not exported into traces, server APIs or SSE. Reproduce the problem in a focused business test; use ToubaHandlerError for a deliberately safe public diagnostic.

The option requires an explicit dev run plan, resolved through --project or supplied with --run-plan. Production, required locks, hardened profiles and Windows are refused. Ambient environment variables and .env do not activate it. Do not publish the local diagnostic file.

Runtime Scope​

Tool binding provides an explicit path from source contract to host effect: declared tool, manifest binding, handler, runtime checks, and trace.

Required platform isolation is configured per binding. Complete permission systems, automatic handler package installation, vulnerability auditing, and dependency graph resolution extend the published static registry. The runtime does not discover handlers automatically.