Documentation•Reference
HazelJS Agent Gatekeeper Package
HazelJS Agent Gatekeeper is the runtime authorization and policy-enforcement layer that controls every tool action attempted by an agent.
Every tool call authorized before execution.
Quick Reference
- Purpose: Deterministic per-invocation authorization before protected tool execution.
- When to use: Any agent tool that mutates data, spends money, crosses tenants, or is destructive.
- Key APIs:
AgentGatekeeper,evaluate,execute,simulate,fromFunction,fromHazelTool,fromSkillgate,protectMcpInvoke,createToolExecutorGate,createAuditTransportSink,createOtelAuditSink,createRedisApprovalProvider. - Dependencies:
zod,yaml. Optional peers:@hazeljs/agent,@hazeljs/skillgate,@hazeljs/audit,@opentelemetry/api. - Common mistakes: Trusting
input.tenantId;mode: 'audit'in production; wrapping MCP withoutprotectMcpInvoke;InMemoryAuditSink/InMemoryApprovalProviderin a multi-replica deployment.
Installation
npm install @hazeljs/agent-gatekeeper
Minimal example
import { AgentGatekeeper, fromFunction, ConsoleAuditSink } from '@hazeljs/agent-gatekeeper';
const gatekeeper = new AgentGatekeeper({
mode: 'enforce',
defaultDecision: 'deny',
policies: [
{
id: 'refund-agent-stripe-policy',
version: '1.0.0',
match: { agents: ['refund-agent'], tools: ['stripe.refund'] },
rules: {
allowWhen: ({ input, context }) =>
input.amount <= 100 && input.tenantId === context.tenantId,
requireApprovalWhen: ({ input }) => input.amount > 50,
},
},
],
auditSink: new ConsoleAuditSink(),
});
await gatekeeper.execute({ context, tool: fromFunction('stripe.refund', refund) });
ConsoleAuditSink writes JSON to stdout (ship with your log collector). InMemoryAuditSink is tests-only.
Production (horizontal scale)
Authorization is stateless: the same policies + trusted ToolInvocationContext produce the same decision on every replica. Audit and approvals must be shared.
import { KafkaAuditTransport } from '@hazeljs/audit';
import {
AgentGatekeeper,
CompositeAuditSink,
ConsoleAuditSink,
createAuditTransportSink,
createOtelAuditSink,
createRedisApprovalProvider,
} from '@hazeljs/agent-gatekeeper';
import { trace } from '@opentelemetry/api';
const gatekeeper = new AgentGatekeeper({
mode: 'enforce',
defaultDecision: 'deny',
policies: [refundPolicy],
auditSink: new CompositeAuditSink([
new ConsoleAuditSink(),
createAuditTransportSink(
new KafkaAuditTransport({
sender: kafkaProducer,
topic: 'hazel.gatekeeper.audit',
key: (event) => String(event.resourceId ?? event.actor?.id ?? ''),
})
),
createOtelAuditSink({ trace }),
]),
approvalProvider: createRedisApprovalProvider(redis),
});
| Audit sink | Scale | Notes |
|---|---|---|
InMemoryAuditSink | No | Tests only. Lost on restart, split per replica. |
ConsoleAuditSink | Yes, via log shipper | Default. JSON stdout → collector. |
createAuditTransportSink(KafkaAuditTransport) | Yes | Shared topic. Awaited; fail-closed in enforce. |
createOtelAuditSink | Yes | Spans to the collector. |
| Approval provider | Scale |
|---|---|
InMemoryApprovalProvider | No — tests / single process |
createRedisApprovalProvider(redis) | Yes — create / resolve / consume on any replica |
createApprovalStoreProvider(RedisApprovalStore) | Yes — via @hazeljs/agent |
createHumanTaskProvider(sqlHumanTasks) | Yes for get/resolve; prefer Redis for atomic consume |
Resume after HITL on another replica:
await replicaB.resolve(approvalId, 'approved', 'operator-1');
await replicaA.execute({
context: { ...context, approvalToken: approvalId },
tool,
});
CLI
hazel gatekeeper validate --config agent-gatekeeper.yaml
hazel gatekeeper simulate --agent refund-agent --tool stripe.refund --input input.json
hazel gatekeeper explain invocation.json
Never executes tools.
Guide
Architecture, policy authoring, approvals, adapters, and rollout: Agent Gatekeeper guide.