Skip to main content
Custom policies turn a failure pattern from your traces or audits into a decision that runs while an agent works. A policy can allow an action, give the agent guidance, or deny the action before it causes another incident. Use a custom policy when the behavior depends on your tools, paths, commands, environments, or operating rules. Check the built-in policy catalog first so you do not recreate an existing control.

Author a custom policy

  1. Go to Admin → policy editor, select New policy, and describe the failure you want to prevent.
  2. Add the policy source, then test expected matches and safe non-matches in the editor. Resolve every validation error.
  3. Save the draft and select Publish version to create an immutable version.
  4. Go to Admin → enforcement, deploy the version to a test machine in observe mode, and verify its decisions under Observe → policy before enforcing it. The policy editor used to author and publish a custom policy.

Start with a narrow rule

This policy blocks destructive Kubernetes commands only when the command targets production. Everything outside that exact failure mode returns allow().
Good policies are narrow enough to explain in one sentence. Match the observable action—not the intent you hope the agent had—and return allow() as soon as the rule does not apply.

Choose a decision

Write the reason for the agent that must recover. Explain what was detected and what it should do instead.
Do not use instruct() for a safety boundary. Guidance delivery varies by agent harness. Use deny() when the action must be prevented.

Policy object

Filter tools inside fn. match.toolNames is not part of the public custom-policy type.

Policy context

Every policy receives a PolicyContext. Treat every optional value as genuinely optional. Agent versions and event types do not all provide the same fields.

Common tool inputs

Failproof AI normalizes common tools across supported harnesses so a policy can usually use one input shape. Use defensive coercion because tool input values are typed as unknown:

Choose the event

Event availability and blocking behavior depend on the agent harness. See Agent harnesses before relying on an event across a mixed fleet.
SessionStart, SessionEnd, UserPromptSubmit, PreToolUse, PermissionRequest, PermissionDenied, PostToolUse, PostToolUseFailure, Notification, SubagentStart, SubagentStop, TaskCreated, TaskCompleted, Stop, StopFailure, TeammateIdle, InstructionsLoaded, ConfigChange, CwdChanged, FileChanged, WorktreeCreate, WorktreeRemove, PreCompact, PostCompact, Elicitation, ElicitationResult, UserPromptExpansion, PostToolBatch, and Setup.

Author common policy patterns

Block writes to protected paths

Give non-blocking guidance

Gate session completion

A denied Stop event can make the agent retry. Only gate on a condition the agent can satisfy in the current environment, and bound every subprocess or network call.

Load policy files

Convention files

Convention files load automatically:
  • Project and user policy directories are both loaded.
  • Files load alphabetically within each directory.
  • A file must end in policies.js, policies.mjs, or policies.ts.
  • Multiple customPolicies.add() calls in one file are supported.
  • Relative imports from local modules are supported.
  • Project policies can be committed so the same rules follow the repository.

Explicit files

Use explicit paths when validation or configuration should name the entry file directly:
Explicit files load first, followed by project convention files and then user convention files. A file discovered through both paths is loaded once.

Validate and test

Validation executes the module through the production loader and confirms that it registers at least one policy.
Validation catches missing files, syntax errors, unresolved imports, top-level exceptions, and module-load timeouts. It does not prove that your match logic is correct. Test at least these cases:
  • One action that must match and produce the intended policy reason.
  • One nearby but safe action that must return allow().
  • Missing or malformed tool fields.
  • Alternate command syntax, paths, quoting, casing, and whitespace.
  • An unavailable subprocess or network dependency.
Attribute the result to your custom policy under Observe → policy. A blocked test is not sufficient if a different built-in policy made the decision.

Runtime behavior

  • Built-in policies evaluate before custom policies.
  • The first deny stops further policy evaluation.
  • Multiple instruct results can be combined when no policy denies the event.
  • A policy function has a 10-second execution deadline.
  • A thrown exception or timeout is logged and treated as allow().
  • A convention file that fails to load is skipped; other custom files and built-in policies continue.
  • Top-level module loading also has a 10-second deadline.
  • Cloud observe mode runs the policy but records a non-allow decision without enforcing it.
Keep policy modules deterministic and quick. Avoid top-level network calls or server startup. Bound work inside fn, catch dependency failures, and choose deliberately whether that failure should allow or deny the operation.

API exports

TypeScript exports PolicyContext, PolicyResult, CustomHook, PolicyDecision, and PolicyFunction.

Deploy custom policies

Publish a version, deploy it in observe mode, verify decisions, and move to enforcement.