Skip to main content
A policy doesn’t have to live in YAML. You can construct the same validated model in Python, which is handy for tests, generated policies, and keeping policy next to the code it governs.

Three ways to build a policy

From a dict — the model validates it (including every constraint’s grammar):
With PolicyBuilder — fluent, and C(...) gives you type-checked constraints instead of hand-written strings:
C covers every operator: <= < > >= == !=, .is_in([...]), .not_in([...]), .count(), and cross-field comparisons (C("args.max") >= C("args.min")). Each constraint is validated the moment you write it, so a typo raises at that line — not later at enforcement. Role-aware, with RolePolicyBuilder — produces a PolicySet:

Gate network egress

net_allow and net_approve are builder sugar for the egress plane. They render a host/scheme/port allowlist into ordinary net.http_request constraints, so an egress rule enforces the same way in both the pydantic and WASM engines.
subdomains matches the apex and any child (example.com and *.example.com). A host restriction is required: pass hosts=, subdomains=, or any_host=True. Calling net_allow() with only a scheme or port filter raises, because it would authorize every host.

Restrict file tools to paths (file_scope)

The file tools read_file, write_file, edit_file (argument file_path), glob and grep (argument path) accept a file_scope that limits which paths they reach:
  • tools.<name>.file_scope.denied_paths wins: a path matching it is denied even if file_scope.allowed_paths matches too.
  • With file_scope.allowed_paths set, a path that matches none of its patterns is denied.
  • A call without the path argument is denied.
file_scope is not a security boundary yet. Its path matching is being reworked: today some spellings of a path, such as ../, absolute paths or symlinks, can reach files the patterns were meant to exclude. Use it to steer an agent away from files, and rely on the workspace sandbox to contain it.
A denied call names the scope in its hint:
file_scope runs only on the default Pydantic engine. The WASM/Rego engine doesn’t support it yet, so hexgate policy validate and hexgate policy build reject a policy that uses it rather than produce a bundle that silently drops the path check. Keep it in policies you apply in code, and leave it out of YAML you build into bundles.

Unit-test a policy

The assert_* helpers evaluate a policy the same way the runtime enforces it:
For a PolicySet, pass role=:
The builder and C emit the exact constraint strings the YAML parser accepts, so a policy built in code enforces identically to the same policy in YAML — there is only one grammar.