Skip to content

Identity, authority and human approval

An authorization record has meaning only when supplied by a trusted component. The coordinator calls your authorizer for every command and replaces caller-supplied context. It also replaces policy, mandatoryChecksOk and authorizationCheckedAt on admission, dispatch and retry.

Return allowed, policy, mandatoryChecksOk and context. Context requires actor, policy revision and decision class. TypeScript uses an async callback; Python uses a callable returning the same JSON-shaped fields; Rust implements Authorizer and returns Authorization, whose field names follow Rust conventions.

Use an authenticated session or workload identity established by the host. Never read a command’s context.actor as proof of who sent it. Bind permission evaluation to the selected mission and resource, not just the command name. A valid “approve” command shape is not evidence that the approver is authorized.

Deny agent attempts to issue new grants · Executable application recipe

import assert from 'node:assert/strict';
import {readFileSync} from 'node:fs';
import {parseContract,type Command} from '@aiws/sdk';
import {SqliteStore} from '@aiws/sdk/sqlite';
import {Coordinator,type Authorizer} from '@aiws/sdk/runtime';
// Demo session comes from the application, never command.context or an event payload.
const session={actor:'agent:builder',isHuman:false};
const humanOnly=new Set(['grant','revokeGrant','approve','withdrawApproval']);
const allowedCommands=new Set(['startRun']); // deliberately narrow teaching policy
const authorize:Authorizer=async(command)=>{
const allowed=allowedCommands.has(command.type)&&(!humanOnly.has(command.type)||session.isHuman);
return {allowed,policy:allowed?'ALLOW':'DENY',mandatoryChecksOk:true,
context:{actor:session.actor,policyRevision:'policy:example:1',decisionClass:'DETERMINISTIC'}};
};
const contract=parseContract(readFileSync('examples/guide/contract.json','utf8'));
const store=new SqliteStore(':memory:',contract);
const coordinator=new Coordinator(store,authorize,()=> '10');
try {
await coordinator.apply({type:'startRun',runId:'r'});
const grant:Command={type:'grant',grant:{id:'g',subject:session.actor,profile:'finite-v1',actions:['write'],resources:['doc'],notBefore:'0',expiresAt:'10000',limit:'100',canDelegate:false,depth:'0'}};
await assert.rejects(coordinator.apply(grant),(e:any)=>e.code==='AUTHORITY_DENIED');
assert.equal(store.snapshot().revision,'1');
assert.equal(store.diagnostics()[0].command.code,'AUTHORITY_DENIED');
} finally {store.close();}

This example deliberately permits only run creation by a demo agent. It rejects grant creation, records a diagnostic, and leaves the mission revision unchanged by the rejection. It is a shape and enforcement example, not a complete organizational policy service. Replace its fixed principal and command allowlist before deployment.

A grant defines an exact subject, finite actions/resources, validity interval, allowance, delegation flag and depth. Child grants cannot expand their parent’s scope, lifetime or allocation. Wildcards, regular expressions and inferred resource containment are not supported. Ancestor revocation is checked again at dispatch.

Reject an expanded child grant · Executable control simulation

import assert from 'node:assert/strict';
import { createMission, parseContract, parseCommand, reduce } from '@aiws/sdk';
// Trusted simulation: this example makes no external calls.
const contract = parseContract(JSON.stringify({
"id": "c",
"missionId": "m",
"aiwsEdition": "0.4",
"profile": "finite-v1",
"budget": "100",
"deadline": "10000",
"criteria": [
"review"
],
"actions": [
"write"
],
"resources": [
"doc"
],
"requiresApproval": false,
"maxAttempts": "2",
"maxAuthorizationAgeMs": "10",
"features": [
"triggers",
"graphs"
]
}));
let state = createMission(contract);
// Step 1
state = reduce(state, parseCommand(JSON.stringify({
"type": "grant",
"grant": {
"id": "g",
"subject": "agent",
"profile": "finite-v1",
"actions": [
"write"
],
"resources": [
"doc"
],
"notBefore": "0",
"expiresAt": "10000",
"limit": "100",
"canDelegate": true,
"depth": "2"
}
})), '10');
// Step 2
assert.throws(() => reduce(state, parseCommand(JSON.stringify({
"type": "grant",
"grant": {
"id": "child",
"subject": "agent",
"profile": "finite-v1",
"actions": [
"write"
],
"resources": [
"doc"
],
"notBefore": "0",
"expiresAt": "10000",
"limit": "100",
"canDelegate": true,
"depth": "2",
"parentId": "g"
}
})), '10'), (error: any) => error.code === 'AUTHORITY_DENIED');
console.log('PASS: grant-scope');

CONTAINED means the supported finite comparison succeeded. INDETERMINATE is not a permissive result. Failure to interpret authority must block admission. Grant containment alone does not authenticate a principal or enforce operating-system and network access.

Approval covers a run and action fingerprint, with expiry and a use count. The fingerprint includes capability, resource, payload and preconditions. Changing those values requires a new material decision rather than reusing approval for the old action.

Bind approval to action material and use count · Executable control simulation

import assert from 'node:assert/strict';
import { createMission, parseContract, parseCommand, reduce } from '@aiws/sdk';
// Trusted simulation: this example makes no external calls.
const contract = parseContract(JSON.stringify({
"id": "c",
"missionId": "m",
"aiwsEdition": "0.4",
"profile": "finite-v1",
"budget": "100",
"deadline": "10000",
"criteria": [
"review"
],
"actions": [
"write"
],
"resources": [
"doc"
],
"requiresApproval": true,
"maxAttempts": "2",
"maxAuthorizationAgeMs": "10",
"features": [
"triggers",
"graphs"
]
}));
let state = createMission(contract);
// Step 1
state = reduce(state, parseCommand(JSON.stringify({
"type": "startRun",
"runId": "r"
})), '10');
// Step 2
state = reduce(state, parseCommand(JSON.stringify({
"type": "grant",
"grant": {
"id": "g",
"subject": "agent",
"profile": "finite-v1",
"actions": [
"write"
],
"resources": [
"doc"
],
"notBefore": "0",
"expiresAt": "10000",
"limit": "100",
"canDelegate": true,
"depth": "2"
}
})), '10');
// Step 3
state = reduce(state, parseCommand(JSON.stringify({
"type": "approve",
"approval": {
"id": "ap",
"runId": "r",
"approver": "owner",
"fingerprint": "sha256:50487a924d1b8f40e5051f0f8d278469acb1cd15d08dbef8f1010e7f54ae9ef0",
"expiresAt": "1000",
"uses": "1"
}
})), '10');
// Step 4
state = reduce(state, parseCommand(JSON.stringify({
"type": "admit",
"runId": "r",
"operationId": "o",
"attemptId": "a",
"grantId": "g",
"subject": "agent",
"action": {
"capability": "write",
"resource": "doc",
"payload": {
"value": 1
},
"preconditions": {
"revision": 1
}
},
"amount": "10",
"authorizationCheckedAt": "10",
"policy": "ALLOW",
"mandatoryChecksOk": true,
"approvalId": "ap"
})), '10');
// Step 5
assert.throws(() => reduce(state, parseCommand(JSON.stringify({
"type": "admit",
"runId": "r",
"operationId": "o2",
"attemptId": "a2",
"grantId": "g",
"subject": "agent",
"action": {
"capability": "write",
"resource": "doc",
"payload": {
"value": 1
},
"preconditions": {
"revision": 1
}
},
"amount": "10",
"authorizationCheckedAt": "10",
"policy": "ALLOW",
"mandatoryChecksOk": true,
"approvalId": "ap"
})), '10'), (error: any) => error.code === 'APPROVAL_CONSUMED');
// Step 6
state = reduce(state, parseCommand(JSON.stringify({
"type": "withdrawApproval",
"approvalId": "ap"
})), '10');
// Step 7
assert.throws(() => reduce(state, parseCommand(JSON.stringify({
"type": "dispatch",
"attemptId": "a",
"authorizationCheckedAt": "10",
"policy": "ALLOW",
"mandatoryChecksOk": true
})), '10'), (error: any) => error.code === 'APPROVAL_INVALID');
console.log('PASS: approval');

The SDK binds approval use to logical operations, not every retry attempt. It rechecks current approval validity before dispatch. It does not send an approval notification or authenticate the approver. Store the human decision and relevant evidence in your application, and issue the command through a policy that verifies the human’s authority.

Engine rule: humans control permissions and resource limits

Section titled “Engine rule: humans control permissions and resource limits”

The proposed engine requires human approval for any agent-requested change to its permissions or resource limits. Enforce this in the trusted application policy; the low-level SDK contains no built-in concept of an authenticated human. Dynamic graph proposals must not smuggle in new grants, reset budgets or choose an alternate policy revision. Read engine decisions for the adopted design direction.