Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Tools and Isolation

A Tool is an external capability that agents can invoke during execution. Orloj provides a standardized tool contract, multiple isolation backends, and runtime controls for timeout, retry, and risk classification.

Defining a Tool

Tools are declared as resources that describe the tool's endpoint, auth requirements, risk level, and runtime configuration.

apiVersion: orloj.dev/v1
kind: Tool
metadata:
  name: web_search
spec:
  type: http
  endpoint: https://api.search.com
  auth:
    secretRef: search-api-key

For tools that require isolation and runtime controls:

apiVersion: orloj.dev/v1
kind: Tool
metadata:
  name: wasm_echo
spec:
  type: wasm
  capabilities:
    - wasm.echo.invoke
  risk_level: high
  runtime:
    isolation_mode: wasm
    timeout: 5s
    retry:
      max_attempts: 1
      backoff: 0s
      max_backoff: 1s
      jitter: none

Key Fields

FieldDescription
typeTool type. Determines the transport and execution model. See below.
endpointThe tool's network endpoint.
capabilitiesDeclared operations this tool provides. Used for permission matching.
risk_levellow, medium, high, or critical. Affects default isolation mode.
runtime.isolation_modeExecution isolation backend (see below).
runtime.timeoutMaximum execution time. Defaults to 30s.
runtime.retryRetry policy for failed invocations.
auth.secretRefReference to a Secret resource for tool authentication.

Tool Types

Tool.spec.type determines how the runtime communicates with the tool. Six types are supported:

TypeTransportContractUse case
httpHTTP POST to endpointRaw body or ToolExecutionResponseSimple API integrations. Default when omitted.
externalHTTP POST to endpointStrict ToolExecutionRequest / ToolExecutionResponseTools running as standalone microservices that need the full execution context.
grpcUnary gRPC call to endpointToolExecutionRequest / ToolExecutionResponse as JSON over orloj.tool.v1.ToolService/ExecuteTeams that prefer gRPC for tool communication.
webhook-callbackHTTP POST to endpoint, then poll {endpoint}/{request_id}ToolExecutionRequest / ToolExecutionResponseLong-running tools, batch jobs, or tools that require human-in-the-loop steps.
mcpJSON-RPC 2.0 via stdio or HTTPMCP tools/call / tools/listTools exposed by MCP servers. Auto-generated by the McpServer controller.
queueReserved for future use--Planned for message-queue-backed tools.

All types flow through the same governed runtime pipeline -- policy enforcement, retry, timeout, auth injection, and error taxonomy behave identically regardless of tool type.

Unknown type values are rejected at apply time.

MCP

The mcp type represents tools provided by an MCP (Model Context Protocol) server. These tools are auto-generated by the McpServer controller -- you do not create them manually. Each type=mcp tool carries mcp_server_ref (the McpServer that owns it) and mcp_tool_name (the tool name on the MCP server).

At invocation time, the MCPToolRuntime resolves the server reference, obtains a session from the McpSessionManager, and sends a tools/call JSON-RPC 2.0 request through the appropriate transport (stdio or Streamable HTTP).

MCP tools also carry description and input_schema from the MCP server's tools/list response. These are propagated to the model gateway so the LLM receives rich, structured tool definitions instead of generic parameter schemas.

See the Connect an MCP Server guide for a complete walkthrough.

HTTP (default)

The http type sends the agent's tool input as an HTTP POST body to spec.endpoint. The runtime accepts both raw text responses and structured ToolExecutionResponse JSON envelopes. Auth is injected as an Authorization: Bearer header when auth.secretRef is configured.

External

The external type sends the full ToolExecutionRequest contract envelope as JSON to spec.endpoint and expects a ToolExecutionResponse back. This gives the external service access to the full execution context (task ID, agent, namespace, trace IDs, attempt number). Use this when your tool needs to be aware of the Orloj execution context.

gRPC

The grpc type calls orloj.tool.v1.ToolService/Execute as a unary gRPC method on spec.endpoint, using a JSON codec. The request and response payloads are the same ToolExecutionRequest / ToolExecutionResponse envelopes as external. Use this when your tool infrastructure is gRPC-native.

Webhook-Callback

The webhook-callback type supports asynchronous tool execution:

  1. The runtime POSTs a ToolExecutionRequest to spec.endpoint.
  2. The tool returns 202 Accepted (or 200 OK with an immediate result).
  3. If 202: the runtime polls {endpoint}/{request_id} at regular intervals until a ToolExecutionResponse with a terminal status arrives, or the configured timeout expires.

This is useful for tools that take minutes to complete (e.g., batch processing, code review, CI pipeline triggers) or that require external approval before returning a result.

Isolation Modes

Isolation modes control the execution boundary of a tool, independent of tool type.

ModeDescriptionDefault for
noneDirect execution in the worker process. The http type makes real HTTP calls; other types use their respective transports.low and medium risk tools
sandboxedRestricted container execution with secure defaults: read-only filesystem, no capabilities, no privilege escalation, no network, non-root user, memory/CPU/pids limits.high and critical risk tools
containerEach tool invocation runs in an isolated container. Full filesystem and network isolation.Explicitly configured
wasmTool runs as a WebAssembly module with a host-guest stdin/stdout contract. Memory-safe and deterministic.Explicitly configured

The isolation mode defaults are based on risk_level:

  • low or medium risk: defaults to none
  • high or critical risk: defaults to sandboxed

You can always override the default by setting runtime.isolation_mode explicitly.

Sandboxed Defaults

When isolation_mode is sandboxed, the container backend enforces these secure defaults:

  • --read-only filesystem
  • --cap-drop=ALL (no Linux capabilities)
  • --security-opt no-new-privileges
  • --network none (no network access)
  • --user 65532:65532 (non-root)
  • --memory 128m
  • --cpus 0.50
  • --pids-limit 64

These defaults can be overridden with --tool-container-* flags on orlojd and orlojworker, but the default posture is restrictive.

Tool Contract v1

Every tool interaction follows a standardized request/response envelope. This contract ensures tools are portable, testable, and observable regardless of the isolation backend.

Request envelope (sent to the tool):

{
  "request_id": "req-abc-123",
  "tool": "web_search",
  "action": "invoke",
  "parameters": {
    "query": "enterprise AI adoption trends"
  },
  "auth": {
    "type": "bearer",
    "token": "sk-..."
  },
  "context": {
    "task": "weekly-report",
    "agent": "research-agent",
    "attempt": 1
  }
}

Response envelope (returned from the tool):

{
  "request_id": "req-abc-123",
  "status": "success",
  "result": {
    "data": "..."
  }
}
Error response:
{
  "request_id": "req-abc-123",
  "status": "error",
  "error": {
    "tool_code": "rate_limited",
    "tool_reason": "API rate limit exceeded",
    "retryable": true
  }
}

The tool contract defines a canonical error taxonomy with tool_code, tool_reason, and retryable fields, enabling the runtime to make intelligent retry decisions.

WASM Tools

WASM tools communicate over stdin/stdout using the same JSON envelope contract. The host writes the request to the module's stdin and reads the response from stdout. This provides memory-safe, deterministic execution with no filesystem or network access unless explicitly granted.

See the WASM Tool Module Contract v1 for the full specification.

Error Taxonomy

Tool failures use a canonical error taxonomy with three fields:

FieldPurpose
tool_codeMachine-readable error code (e.g. rate_limited, unsupported_tool, secret_resolution_failed)
tool_reasonHuman-readable explanation
retryableWhether the runtime should retry the invocation

HTTP status codes are mapped automatically: 429 and 5xx are retryable, 4xx are not. HTTP 401 maps to auth_invalid and 403 maps to auth_forbidden -- both non-retryable. All tool types share the same taxonomy, so policy and observability behave consistently.

Auth Profiles

Tools support four authentication profiles via spec.auth.profile:

ProfileSecret formatInjection
bearer (default)Single token valueAuthorization: Bearer <token>
api_key_headerSingle key valueCustom header via spec.auth.headerName
basicusername:passwordAuthorization: Basic <base64>
oauth2_client_credentialsMulti-key secret with client_id and client_secretToken exchange at spec.auth.tokenURL, then bearer injection

When spec.auth.secretRef is set without an explicit profile, the default is bearer for backward compatibility. See the Tool Contract v1 for full auth binding details.

Secret Rotation

Secret resolution is performed fresh per tool invocation -- there is no caching of raw secret values. If a secret is rotated between invocations, the new value takes effect on the next call without requiring a restart.

For oauth2_client_credentials, access tokens are cached with a TTL derived from the token endpoint's expires_in response. Tokens are evicted on expiry or when the tool endpoint returns HTTP 401, triggering a fresh token exchange.

Retry and Timeout

Each tool can configure its own retry policy independently of the task-level retry:

runtime:
  timeout: 5s
  retry:
    max_attempts: 3
    backoff: 1s
    max_backoff: 30s
    jitter: full

Retry uses capped exponential backoff. The jitter field controls randomization: none (deterministic), full (random between 0 and backoff), or equal (half deterministic, half random).

Governance Integration

Tool invocations are gated by the governance layer. An agent must have the required permissions (via AgentRole) to invoke a tool, and the tool must not be blocked by any applicable AgentPolicy. Unauthorized calls fail closed with a tool_permission_denied error.

Operation Classes

Tools can declare operation classes via spec.operation_classes (e.g. read, write, delete, admin). When omitted, the default is ["read"] for low/medium risk tools and ["write"] for high/critical risk tools.

Operation classes are used by ToolPermission.spec.operation_rules to define per-class policy verdicts:

  • allow: proceed with the tool call (default).
  • deny: block the call with a permission_denied error.
  • approval_required: pause the task and create a ToolApproval resource. An external actor (human or system) must approve or deny the request before the task can continue.

When multiple rules match, the most restrictive verdict wins: deny > approval_required > allow.

Approval Workflow

When a tool call is flagged as approval_required, the following happens:

  1. The GovernedToolRuntime returns an ErrToolApprovalRequired sentinel error.
  2. The task controller transitions the task to the WaitingApproval phase.
  3. A ToolApproval resource is created with details about the pending call.
  4. An external actor approves or denies the request via the API (POST /v1/tool-approvals/{name}/approve or /deny).
  5. The task controller reconciles the approval status:
    • Approved: task resumes to Running.
    • Denied: task transitions to Failed with approval_denied.
    • Expired (TTL elapsed): task transitions to Failed with approval_timeout.

Approval-related outcomes are non-retryable and do not consume retry budget.

Related Resources