Core primitives
The two main primitives arecreate_agent(...) and @agent_tool(...). Use them
when you want to define everything directly in Python.
Wrap an existing framework agent
Already have an OpenAI Agents / LangChain / Google ADK / Pydantic AI agent? Wrap it once and you’re done:- Tool-call enforcement at every tool boundary (
PolicyEnforcer.decide()) - Role resolution from the active context’s
user_rolesat call time (every role evaluated, most permissive wins) - Per-request biscuit attenuation
- Langfuse traces tagged with the caller’s identity
Env vars: that is the whole config surface
No config object to instantiate, no
enforce_policy(...) call to remember on the
platform path. The adapter / loader threads it all through. The full list of env
vars lives in the environment reference.
Connecting to Hexgate. The key and the URL are coupled: a fty_live_… key
only verifies against the platform instance that minted it.
- Hexgate Cloud (default): set
HEXGATE_API_KEYto the key from app.hexgate.ai. LeaveHEXGATE_API_URLunset — it defaults to the cloud, so this is the zero-infra path. - Self-hosted / local platform: additionally set
HEXGATE_API_URL=http://localhost:8000(or your host), and use a key minted by that platform.
Two carve-outs worth knowing
- Per-call identity stays explicit.
HexgateContextis the one piece the adapter can’t infer from env, because it’s per-request, not per-process. One line wrapping each call (hexgate_context=HexgateContext(...)kwarg on adapters,async with HexgateContext(...)for native). See Request context. approval_requiredtools. If the policy uses that mode, dev decides what happens — passapproval_handler=(True / False / callable) when wrapping. The CLI default isaskfor both commands:hexgate chatprompts the TTY, andhexgate serveroutes the request to the connected Playground (pass--approval-mode auto-approvefor headless runs). See Approval-required tool calls.
Define agents in code and resolve them by name
If you want the CLI and shared loader to resolve acreate_agent(...) agent by
name, register it first and then load it through load_agent(...).
A small end-to-end example registry lives in examples/file_agents.py and
examples/research_agents.py. It demonstrates:
- building one agent with
create_agent(...)only - building another with
create_agent(...)plusenforce_policy(...) - building a research agent with approval-gated file writes via
enforce_policy(..., approval_handler=...) - registering it with
register_agent_factory(...)and loading it throughload_agent(...)
Local agents
The CLI discovers local agents from./<agent_dir>/agent.yaml,
./agents/<agent_dir>/agent.yaml, and ./examples/<agent_dir>/agent.yaml. This
repo ships a demo agent at examples/example_agent/, so from the project root:
Stream results
For direct Python usage, the simplest runtime path is:stream_agent(...) yields normalized events for assistant text deltas, tool
lifecycle, and final run completion.