Are you an LLM? You can read better optimized documentation at /docs/agent-guard/custom-runtimes/agent-definition.md for this page in Markdown format
Declare a runtime in an agent definition
The agent definition is where a custom runtime gets its authority. It decides which image runs, which models it may call and with which credentials, which tools and skills it gets, which policies apply, and which values reach it. For the definition format in general, see What is an agent definition.
A complete example
yaml
apiVersion: agentguard.jozu.dev/v1
kind: AgentDefinition
metadata:
name: triage-agent
spec:
framework: jozu.ml/acme/triage-agent:1.0.0
needs:
- name: OPENAI_API_KEY # read from the host environment
- name: TICKET_QUEUE
from:
text: platform-oncall # a literal
includes:
- name: assistant
type: llm
source:
model: openai/gpt-4o-mini
env:
OPENAI_API_KEY: ${needs.OPENAI_API_KEY}
- name: tickets
type: mcp
source:
modelkit: jozu.ml/acme/tickets-mcp:2.1.0
- name: runbooks
type: skill
source:
modelkit: jozu.ml/acme/runbook-skills:1.4.0
- name: triage-rules
type: policy
source:
modelkit: jozu.ml/acme/triage-policies:1.0.0The application in jozu.ml/acme/triage-agent asks for the model assistant, calls the tickets tools, reads the runbooks skills, and finds TICKET_QUEUE in its environment. It never sees OPENAI_API_KEY: that value goes to the Jozu AI Gateway.
spec.framework
spec.framework names either a framework Agent Guard integrates (claude-code, codex, openclaw, antigravity, the same names agentguard run takes) or a container image.
An image reference starts with its registry host: a name containing . or :, or localhost. Agent Guard assumes no default registry, so a short reference such as python:3.12 is refused.
yaml
framework: jozu.ml/acme/triage-agent@sha256:3b1f...Referencing the image by digest is recommended, so that every run of the definition uses the same image.
The image must meet the requirements in Build a runtime image. Agent Guard checks them before the microVM boots.
When a derived definition inherits from a base, it inherits spec.framework. If it restates it, the value must match the base's exactly, tag or digest included.
llm modules
Each llm module is a model the application may call, registered with the Jozu gateway by the module's name. The application asks the Jozu gateway for assistant; the Jozu gateway sends the request to the module's provider, as the module's model, with the module's credential. A model name that matches no module is refused.
yaml
- name: assistant
type: llm
source:
model: openai/gpt-4o-mini # <provider>/<model>
endpoint: https://api.openai.com # optional; the provider's server root
env:
OPENAI_API_KEY: ${needs.OPENAI_API_KEY}source.model is <provider>/<model>. The Jozu gateway sends the part after the first / to the provider. It supports the providers anthropic, bedrock, cohere, gemini, huggingface, openai, and replicate, but only anthropic, openai, and gemini modules can be given a credential.
source.endpoint is optional and overrides the provider's default URL, for an OpenAI-compatible server of your own, for example. Give the server's root, such as https://llm.internal.example.com. The Jozu gateway appends the API path itself, so an endpoint ending in /v1 produces a request to /v1/v1/....
env holds the module's credential, under the name the provider uses:
| Provider | Variable |
|---|---|
anthropic | ANTHROPIC_API_KEY |
openai | OPENAI_API_KEY |
gemini | GEMINI_API_KEY or GOOGLE_API_KEY (one, not both) |
Each value is a literal or exactly one ${needs.NAME} reference. A module's env values are delivered to the Jozu gateway, not to the agent container, and the run prints which names were withheld from the application. env on an llm module is accepted only when spec.framework is an image; a CLI agent gets its credentials through --pass-env or its own login (see Pass credentials).
A module with no credential passes the request's model name to the provider unchanged, so the module's name must be the provider's model name. Module names allow only letters, digits, ., -, and _, so a model whose name has another character, such as meta-llama/Llama-3.1-8B-Instruct on an OpenAI-compatible server, needs a credential, even a placeholder the server ignores.
A module the Jozu gateway cannot serve is dropped for the session, with a line in the boot log naming the module and the reason, and a request for it is refused like any undeclared model. That happens when a module has no provider prefix and no endpoint, names a provider outside the list above, declares a local ModelKit model (source.modelkit), declares no credential for a provider that needs one, or declares more than one env variable.
A module named after a provider, such as openai, gets a renamed entry inside the Jozu gateway. The application still calls it by the module name.
mcp modules
mcp modules work as they do for a CLI agent: a source.modelkit bundle runs inside the microVM, and a source.endpoint with transport: http reaches a remote server. tools: narrows a module to the tools it lists. Local MCP servers run outside the application's container, under their own account, and see the workspace at the same path the application does.
The application reaches every module's tools through one gateway endpoint, and every call is evaluated against the definition's policies. See Calling tools.
skill modules
Each skill module is copied into the container's skills directory, one directory per skill, read-only. The application reads them itself. If two skills have the same name, the second is dropped and the boot log says so.
policy modules
policy modules apply to a custom runtime as they do to any agent. GuardrailPolicy is evaluated on model requests and responses, and ToolPolicy on MCP tool calls, together with the policies installed with agentguard policy add. A derived definition cannot remove them. See How policies work.
Policy sees what passes through the Jozu gateway: model requests and MCP tool calls. An action the application takes directly, without the Jozu gateway, is governed only if the application asks for a decision itself. See Asking for a decision on your own actions.
spec.needs
spec.needs is the only way a value from the host reaches the application. Each need names a variable, and its value comes from a resolver:
yaml
needs:
- name: GITHUB_TOKEN # from the host variable GITHUB_TOKEN
- name: TICKET_API_TOKEN
from:
envFrom: ACME_TICKETS_PAT # from a differently named host variable
- name: TICKET_QUEUE
from:
text: platform-oncall # a literal
- name: SENTRY_DSN
optional: true # absent, rather than an error, if unset- A need with no
fromreads the host environment variable of the same name. - A required need that does not resolve stops the run before the microVM boots, naming the host variable to set.
- An optional need that does not resolve is absent from the container, not empty.
- A need an
llmmodule references inenvgoes to the Jozu gateway and is not set in the container. - A need's
targetdefaults toenv, the only target that is delivered; see Limitations.
The container's environment is built only from the needs the definition declares, so nothing can be added to it at run time (--pass-env and --pass-cloud-creds do not reach it), and the definition is a complete list of what the application receives.
