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.
Authorizer contract
Section titled “Authorizer contract”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 policyconst 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();}use aiws_sdk::*;use aiws_sdk::runtime::*;use aiws_sdk::sqlite::SqliteStore;use serde_json::json;struct SessionPolicy;impl Authorizer for SessionPolicy { fn authorize(&mut self,command:&Command,_:&Snapshot,_:&str)->Result<Authorization>{ // Deliberately narrow demo agent policy. Identity comes from trusted host state. let allowed=command.as_value()["type"]=="startRun"; Ok(Authorization{allowed,policy:if allowed{"ALLOW"}else{"DENY"}.into(),mandatory_checks_ok:true, context:json!({"actor":"agent:builder","policyRevision":"policy:example:1","decisionClass":"DETERMINISTIC"})}) }}struct FixedClock;impl Clock for FixedClock{fn now_ms(&self)->String{"10".into()}}fn main()->std::result::Result<(),Box<dyn std::error::Error>>{ let contract=Contract::parse(&std::fs::read_to_string("examples/guide/contract.json")?)?; let store=SqliteStore::open(":memory:",Some(&contract))?; let mut coordinator=Coordinator::new(store,SessionPolicy,FixedClock); coordinator.apply(&Command::from_value(json!({"type":"startRun","runId":"r"}))?,None)?; let grant=Command::from_value(json!({"type":"grant","grant":{"id":"g","subject":"agent:builder","profile":"finite-v1","actions":["write"],"resources":["doc"],"notBefore":"0","expiresAt":"10000","limit":"100","canDelegate":false,"depth":"0"}}))?; assert_eq!(coordinator.apply(&grant,None).unwrap_err().code,"AUTHORITY_DENIED"); assert_eq!(coordinator.store.snapshot()?.as_value()["revision"],"1"); assert_eq!(coordinator.store.diagnostics()?[0]["command"]["code"],"AUTHORITY_DENIED"); Ok(())}from pathlib import Pathfrom aiws import parse_contract,AiwsErrorfrom aiws.sqlite import SqliteStorefrom aiws.runtime import Coordinator# Identity is trusted application state, not a caller-supplied command field.session={'actor':'agent:builder','isHuman':False}def authorize(command,state,now): allowed=command['type']=='startRun' # narrow demo policy; everything else is denied return dict(allowed=allowed,policy='ALLOW' if allowed else 'DENY',mandatoryChecksOk=True, context=dict(actor=session['actor'],policyRevision='policy:example:1',decisionClass='DETERMINISTIC'))contract=parse_contract(Path('examples/guide/contract.json').read_text())with SqliteStore(':memory:',contract) as store: coordinator=Coordinator(store,authorize,lambda:'10') coordinator.apply(dict(type='startRun',runId='r')) grant=dict(type='grant',grant=dict(id='g',subject=session['actor'],profile='finite-v1',actions=['write'],resources=['doc'],notBefore='0',expiresAt='10000',limit='100',canDelegate=False,depth='0')) try: coordinator.apply(grant) raise AssertionError('expected denial') except AiwsError as error: assert error.code=='AUTHORITY_DENIED' assert store.snapshot()['revision']=='1' assert store.diagnostics()[0]['command']['code']=='AUTHORITY_DENIED'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.
Grants and delegated scope
Section titled “Grants and delegated scope”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 1state = 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 2assert.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');use aiws_sdk::*;use serde_json::json;
fn main() -> Result<()> { // Trusted simulation: no external calls. let contract = Contract::from_value(json!({ "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 mut state = create_mission(&contract)?;
// Step 1 state = reduce(&state, &Command::from_value(json!({ "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 let rejected = Command::from_value(json!({ "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" }})).and_then(|command| reduce(&state, &command, "10")); assert_eq!(rejected.unwrap_err().code, "AUTHORITY_DENIED"); println!("PASS: grant-scope"); Ok(())}from aiws import create_mission, reduce, AiwsError
# Trusted simulation: this example makes no external calls.contract = {'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']}state = create_mission(contract)
# Step 1state = reduce(state, {'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 2try: reduce(state, {'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') raise AssertionError('expected AUTHORITY_DENIED')except AiwsError as error: assert error.code == 'AUTHORITY_DENIED'print('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.
Material-bound action approval
Section titled “Material-bound action approval”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 1state = reduce(state, parseCommand(JSON.stringify({ "type": "startRun", "runId": "r"})), '10');
// Step 2state = 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 3state = reduce(state, parseCommand(JSON.stringify({ "type": "approve", "approval": { "id": "ap", "runId": "r", "approver": "owner", "fingerprint": "sha256:50487a924d1b8f40e5051f0f8d278469acb1cd15d08dbef8f1010e7f54ae9ef0", "expiresAt": "1000", "uses": "1" }})), '10');
// Step 4state = 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 5assert.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 6state = reduce(state, parseCommand(JSON.stringify({ "type": "withdrawApproval", "approvalId": "ap"})), '10');
// Step 7assert.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');use aiws_sdk::*;use serde_json::json;
fn main() -> Result<()> { // Trusted simulation: no external calls. let contract = Contract::from_value(json!({ "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 mut state = create_mission(&contract)?;
// Step 1 state = reduce(&state, &Command::from_value(json!({ "type": "startRun", "runId": "r"}))?, "10")?;
// Step 2 state = reduce(&state, &Command::from_value(json!({ "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, &Command::from_value(json!({ "type": "approve", "approval": { "id": "ap", "runId": "r", "approver": "owner", "fingerprint": "sha256:50487a924d1b8f40e5051f0f8d278469acb1cd15d08dbef8f1010e7f54ae9ef0", "expiresAt": "1000", "uses": "1" }}))?, "10")?;
// Step 4 state = reduce(&state, &Command::from_value(json!({ "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 let rejected = Command::from_value(json!({ "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"})).and_then(|command| reduce(&state, &command, "10")); assert_eq!(rejected.unwrap_err().code, "APPROVAL_CONSUMED");
// Step 6 state = reduce(&state, &Command::from_value(json!({ "type": "withdrawApproval", "approvalId": "ap"}))?, "10")?;
// Step 7 let rejected = Command::from_value(json!({ "type": "dispatch", "attemptId": "a", "authorizationCheckedAt": "10", "policy": "ALLOW", "mandatoryChecksOk": true})).and_then(|command| reduce(&state, &command, "10")); assert_eq!(rejected.unwrap_err().code, "APPROVAL_INVALID"); println!("PASS: approval"); Ok(())}from aiws import create_mission, reduce, AiwsError
# Trusted simulation: this example makes no external calls.contract = {'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']}state = create_mission(contract)
# Step 1state = reduce(state, {'type': 'startRun', 'runId': 'r'}, '10')
# Step 2state = reduce(state, {'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 3state = reduce(state, {'type': 'approve', 'approval': {'id': 'ap', 'runId': 'r', 'approver': 'owner', 'fingerprint': 'sha256:50487a924d1b8f40e5051f0f8d278469acb1cd15d08dbef8f1010e7f54ae9ef0', 'expiresAt': '1000', 'uses': '1'}}, '10')
# Step 4state = reduce(state, {'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 5try: reduce(state, {'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') raise AssertionError('expected APPROVAL_CONSUMED')except AiwsError as error: assert error.code == 'APPROVAL_CONSUMED'
# Step 6state = reduce(state, {'type': 'withdrawApproval', 'approvalId': 'ap'}, '10')
# Step 7try: reduce(state, {'type': 'dispatch', 'attemptId': 'a', 'authorizationCheckedAt': '10', 'policy': 'ALLOW', 'mandatoryChecksOk': True}, '10') raise AssertionError('expected APPROVAL_INVALID')except AiwsError as error: assert error.code == 'APPROVAL_INVALID'print('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.