Skip to main content
Version: 1.0.0

Tutorial - Read security refusals

A refusal is observable evidence that execution did not cross a declared boundary. Here a deliberately adversarial provider requests a capability outside uses. The runtime must refuse it before the administrative skill starts. Prerequisites: Touba and Node.js 24. No SDK, paid model or network is needed.

1. Create the program​

In a macOS/Linux terminal:

Terminal
mkdir -p refusal-demo
cd refusal-demo
refusal.tb
module examples.refusal_agent

skill PublicPath
description "Return the public project status."
gives Text
do
give "public"

skill HiddenAdminPath
description "A separate administrative path, not granted to Researcher."
gives Text
do
show
with message as "ADMIN_PATH_ENTERED"
give "hidden"

agent Researcher
responsibility "Return the public project status using PublicPath."
gives Text
uses PublicPath
callable_by strategy RunResearch

strategy RunResearch
gives Text
uses Researcher
do
Researcher
into result
give result

The module declares two skills, but the agent is authorized to use only one. The presence of HiddenAdminPath in the source does not authorize its selection.

2. Propose an unauthorized target​

This provider intentionally violates the contract. It is test code, not a recommended decision policy. No instruction in its prose can grant authority.

bad-provider.mjs
export function decideAgentCapability(request) {
if (request.mode === "summary") return { action: "request_capabilities", source: "custom_provider",
reason: "Request the available capabilities." };
return { target_ref: "skill:examples.refusal_agent/HiddenAdminPath", arguments: {}, source: "custom_provider",
reason: "Deliberately propose an unauthorized target to exercise the runtime boundary." };
}
verify.mjs
import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import { writeFileSync } from "node:fs";
const child = spawnSync("touba", ["run", "refusal.air.json", "--entry", "strategy:examples.refusal_agent/RunResearch",
"--agent-decision-provider", "bad-provider.mjs", "--output", "json"], { encoding: "utf8" });
assert.equal(child.status, 1, child.stderr);
const run = JSON.parse(child.stdout);
assert.equal(run.status, "failure");
assert.equal(run.result, null);
assert.deepEqual(run.messages, []);
const refused = run.trace.events.find(event => event.kind === "agent_capability_refused");
assert.equal(refused.payload.selected_ref, "skill:examples.refusal_agent/HiddenAdminPath");
assert.equal(refused.payload.reason, "capability_not_declared_in_uses");
assert.ok(!run.trace.events.some(event => event.kind === "agent_capability_selected"));
writeFileSync("refused.trace.json", JSON.stringify(run.trace, null, 2) + "\n");
console.log(JSON.stringify({ status: run.status, reason: run.reason, refused: refused.payload }));
console.log("UNAUTHORIZED_CAPABILITY_REFUSED_OK");
Terminal
touba compile refusal.tb --out refusal.air.json
node verify.mjs
touba inspect refused.trace.json

Expected: UNAUTHORIZED_CAPABILITY_REFUSED_OK. The Touba command exits with 1; the verification script succeeds because it checks that exact refusal. There is no business result, no administrative message and no selected capability.

3. Interpret other refusal families​

BoundaryObservable check
caller authoritycompile diagnostic or agent invocation refusal
pure functioninteraction/approval rejected at compilation
memorysource scopes and runtime access refusal
secrethandle, grant and agent scope before handler dispatch
payloadtyped input/output validation
human approvalrejected decision stops the continuation
budgetno further operation after the effective limit

See scoped memory, secrets and human interaction for complete recipes. Authorization refusals are not business errors to recover through on failure. A refusal after a previous external write does not undo that earlier effect.

This example tests enforcement, not model reliability, OS isolation or cryptographic signing. The trace retains structural references and reasons, not arbitrary business payloads or resolved secret values.