Resource Reference
Stability: beta -- All resource kinds under
orloj.dev/v1are suitable for production use, but their schemas may evolve with migration guidance in future minor releases.
This document describes the current resource schemas in orloj.dev/v1, based on the runtime types and normalization logic in:
resources/agent.goresources/model_endpoint.goresources/resource_types.goresources/graph.go
Common Conventions
- Every resource uses standard top-level fields:
apiVersion,kind,metadata,spec,status. metadata.nameis required for all resources.metadata.namespacedefaults todefaultwhen omitted.- Most resources default
status.phasetoPendingduring normalization.
Resource Kinds
AgentAgentSystemModelEndpointToolSecretMemoryAgentPolicyAgentRoleToolPermissionToolApprovalTaskTaskScheduleTaskWebhookWorker
Agent
spec
model_ref(string): reference to aModelEndpoint(nameornamespace/name).prompt(string): agent instruction prompt.tools([]string): tool names available to the agent.allowed_tools([]string): tools pre-authorized without RBAC. Bypasses AgentRole/ToolPermission checks for listed tools.roles([]string): boundAgentRolenames.memory(object):ref(string): reference to aMemoryresource. This attaches the memory backend to the agent. See Memory.allow([]string): explicit built-in memory operations allowed for the agent:read,write,search,list,ingest.type(string)provider(string)
limits(object):max_steps(int)timeout(string duration)
execution(object): optional per-agent execution contract.profile(string):dynamic(default) orcontract.tool_sequence([]string): required tool names whenprofile=contract. Tracked as a set (order-independent).required_output_markers([]string): strings that should appear in final model output whenprofile=contract. Treated as best-effort: missing markers atmax_stepsproduce a warning, not a hard failure, when all tools completed.duplicate_tool_call_policy(string):short_circuit(default) ordeny. Inshort_circuitmode, duplicate tool calls reuse cached results and inject a completion hint. This applies to all profiles, not justcontract.on_contract_violation(string):observeornon_retryable_error(default). Inobservemode, violations are logged as telemetry events but do not stop execution or deadletter the task.tool_use_behavior(string): Controls what happens after a tool call succeeds. See Tool Use Behavior below.
Tool Use Behavior
The tool_use_behavior field controls whether the model gets another turn after a successful tool call. This is the primary lever for optimizing token usage in tool-calling agents.
| Value | Model calls | When to use |
|---|---|---|
run_llm_again (default) | Tool call + follow-up model call to process the result | The agent needs to interpret, format, or synthesize the tool output before handing off. Most agents need this. |
stop_on_first_tool | Tool call only -- tool output becomes the agent's final output directly | The agent is a relay that calls a tool and passes raw data to the next agent in the pipeline. No interpretation needed. |
run_llm_again (default)
An analyst agent calls an API tool, then needs to produce labeled output from the raw response:
kind: Agent
metadata:
name: analyst-agent
spec:
prompt: "Call the API, then return SUMMARY: and EVIDENCE: labels."
tools:
- external-api-tool
# tool_use_behavior defaults to run_llm_again -- agent gets a
# second model call to read the tool result and produce labels.Step 1: model calls external-api-tool → Step 2: model reads tool result, produces labeled output → done (2 model calls).
stop_on_first_tool
A fetcher agent's only job is to call a tool and pass the raw result downstream:
kind: Agent
metadata:
name: fetcher-agent
spec:
prompt: "Fetch the latest data from the API."
tools:
- external-api-tool
execution:
tool_use_behavior: stop_on_first_tool
# Agent exits immediately after the tool returns.
# Raw tool output becomes the agent's output -- no extra model call.Step 1: model calls external-api-tool → done (1 model call). The next agent in the pipeline receives the raw tool response as context.
stop_on_first_tool:
- The agent needs to produce structured/labeled output from the tool result.
- The agent has multiple tools and may need to call more than one.
- The agent needs to reason about the tool result before responding.
Defaults and Validation
model_refis required.rolesare trimmed and deduplicated (case-insensitive).memory.allowis trimmed, normalized, and deduplicated. It requiresmemory.ref.limits.max_stepsdefaults to10when<= 0.execution.profiledefaults todynamic.execution.duplicate_tool_call_policydefaults toshort_circuit. Applies to all profiles.execution.on_contract_violationdefaults tonon_retryable_error. Set toobservefor safe production rollout.execution.tool_use_behaviordefaults torun_llm_again.execution.tool_sequenceandexecution.required_output_markersare trimmed and deduplicated.- When
execution.profile=contract,execution.tool_sequenceis required. - Tool sequence is tracked as a set: tools may be called in any order.
- When all tools in
tool_sequencecomplete butrequired_output_markersare not satisfied atmax_steps, the task completes with acontract_warningevent instead of deadlettering.
Structured tool protocol: Tool results are sent to the model using the provider's native structured tool calling protocol (OpenAI role: "tool" with tool_call_id, Anthropic tool_result content blocks). This gives the model structured evidence that a tool was already called, preventing unnecessary repeat calls.
profile: dynamic(default): structured tool protocol prevents repeat calls. Succeeded tools are filtered from the available tools list. No YAML changes needed.tool_use_behavior: stop_on_first_tool: for pipeline stages that pass raw data, eliminates all extra model calls (1 model call + 1 tool call total).profile: contract+on_contract_violation: observe: adds guaranteed early completion when all tools succeed plus telemetry for contract deviations.profile: contract+on_contract_violation: non_retryable_error: hard enforcement for critical pipeline stages. Violations deadletter the task.
status
phase,lastError,observedGeneration
Example: examples/resources/agents/*.yaml
AgentSystem
spec
agents([]string): participating agent names.graph(map[string]GraphEdge): per-node routing.
GraphEdge fields:
next(string): legacy single-hop route.edges([]GraphRoute): fan-out routes.to(string)labels(map[string]string)policy(map[string]string)
join(GraphJoin): fan-in behavior.mode:wait_for_allorquorumquorum_count(int, >= 0)quorum_percent(int, 0-100)on_failure:deadletter,skip,continue_partial
Defaults and Validation
graph[*].nextandgraph[*].edges[].toare trimmed.- Route targets are normalized/deduplicated for execution.
joinnormalization defaults:mode->wait_for_allon_failure->deadletterquorum_percentclamped to0..100- invalid values are coerced to safe defaults in graph normalization.
- Runtime task validation additionally checks:
- graph nodes/edges must reference agents in
spec.agents - cyclic graphs require
Task.spec.max_turns > 0 - non-cyclic graphs require at least one entrypoint (zero indegree node)
- graph nodes/edges must reference agents in
status
phase,lastError,observedGeneration
Example: examples/resources/agent-systems/*.yaml
ModelEndpoint
spec
provider(string): provider id (openai,anthropic,azure-openai,ollama,mock, or registry-added providers).base_url(string)default_model(string)options(map[string]string): provider-specific options.auth.secretRef(string): namespaced reference to aSecret.
Defaults and Validation
providerdefaults toopenaiand is normalized to lowercase.base_urldefaults by provider:openai->https://api.openai.com/v1anthropic->https://api.anthropic.com/v1ollama->http://127.0.0.1:11434
optionskeys are normalized to lowercase; keys/values are trimmed.
status
phase,lastError,observedGeneration
Example: examples/resources/model-endpoints/*.yaml
Tool
spec
type(string): tool type. Allowed values:http,external,grpc,webhook-callback,queue,mcp. Unknown values are rejected at apply time.endpoint(string): tool endpoint URL (orhost:portfor gRPC).description(string): human-readable description of the tool. Passed to model gateways for richer tool definitions. Auto-populated for MCP-generated tools.input_schema(object): JSON Schema for tool parameters. Passed to model gateways for structured parameter definitions. Auto-populated for MCP-generated tools.mcp_server_ref(string): name of the McpServer that provides this tool. Required whentype=mcp.mcp_tool_name(string): the tool name as reported by the MCP server'stools/list. Required whentype=mcp.capabilities([]string): declared operations.operation_classes([]string): operation class annotations. Allowed values:read,write,delete,admin. Used byToolPermission.operation_rulesfor per-class policy verdicts.risk_level(string):low,medium,high,critical.runtime(object):timeout(duration string)isolation_mode:none,sandboxed,container,wasmretry.max_attempts(int)retry.backoff(duration string)retry.max_backoff(duration string)retry.jitter:none,full,equal
auth(object):profile(string): auth profile. Allowed values:bearer,api_key_header,basic,oauth2_client_credentials. Defaults tobearerwhensecretRefis set.secretRef(string): namespaced secret reference. Required whenprofileis set.headerName(string): custom header name. Required whenprofile=api_key_header.tokenURL(string): OAuth2 token endpoint. Required whenprofile=oauth2_client_credentials.scopes([]string): OAuth2 scopes.
Defaults and Validation
typedefaults tohttp. Unknown types are rejected with a validation error.mcptype tools are typically auto-generated by the McpServer controller; see Connect an MCP Server.auth.profiledefaults tobearerwhensecretRefis set. Unknown profiles are rejected.auth.headerNameis required whenprofile=api_key_header.auth.tokenURLis required whenprofile=oauth2_client_credentials.capabilitiesare trimmed and deduplicated (case-insensitive).operation_classesare trimmed, lowercased, and deduplicated. Invalid values are rejected. Defaults to["read"]forlow/mediumrisk,["write"]forhigh/criticalrisk.risk_leveldefaults tolow.runtime.timeoutdefaults to30sand must parse as duration.runtime.isolation_modedefaults to:sandboxedforhigh/criticalrisknoneforlow/mediumrisk
runtime.retrydefaults:max_attempts->1backoff->0smax_backoff->30sjitter->none
status
phase,lastError,observedGeneration
Examples:
examples/resources/tools/*.yamlexamples/resources/tools/wasm-reference/wasm_echo_tool.yaml
Secret
spec
data(map[string]string): base64-encoded values.stringData(map[string]string): write-only plaintext convenience input.
Defaults and Validation
stringDataentries are merged intodataas base64 during normalization.- Every
datavalue must be non-empty valid base64. stringDatais cleared after normalization (write-only behavior).
status
phase,lastError,observedGeneration
Examples: examples/resources/secrets/*.yaml
Memory
A Memory resource configures a persistent memory backend that agents can read from and write to using built-in memory tools. See Memory Concepts for a full overview.
spec
type(string): categorization of the memory use case (e.g.vector,kv). Informational in v1.provider(string): backend implementation. Built-in values:in-memory(default): in-process key-value store. No endpoint needed. Data is lost on restart.pgvector: PostgreSQL with the pgvector extension. Full vector-similarity search. Requiresendpoint(Postgres DSN) andembedding_model(ModelEndpoint reference). See pgvector.http: delegates to an external HTTP service. Requiresendpoint. See HTTP Adapter.- Coming soon: Qdrant, Pinecone, Weaviate, Chroma, Milvus. Custom providers can also be registered via the Go provider registry.
embedding_model(string): reference to a ModelEndpoint resource that provides an OpenAI-compatible/embeddingsAPI. Required for vector providers likepgvector. The endpoint'sbase_url,auth, anddefault_modelare used to generate embeddings. Resolved in the same namespace by default; usenamespace/namefor cross-namespace references.endpoint(string): connection string or URL. Forpgvector, a Postgres DSN (e.g.postgres://user@host:5432/db). Forhttp, the adapter service URL. Not needed forin-memory.auth(object):secretRef(string): reference to a Secret resource containing credentials. Forhttp, used as a bearer token. Forpgvector, injected as the Postgres password into the DSN.
Defaults and Validation
providerdefaults toin-memorywhen omitted or empty.endpointis required whenproviderispgvector,http, or any cloud-hosted built-in provider.embedding_modelis required whenproviderispgvector. It must reference a valid ModelEndpoint.- When
auth.secretRefis set, the controller resolves the Secret and passes the token to the provider. - The Memory controller validates the provider, resolves auth, and performs a connectivity check (
Ping). Unsupported providers, missing secrets, or failed connectivity moves the resource toErrorphase.
Built-in Memory Tools
When an Agent references a Memory resource via spec.memory.ref and explicitly grants operations with spec.memory.allow, the runtime exposes the following built-in tools:
| Tool | Description |
|---|---|
memory.read | Retrieve a value by key. |
memory.write | Store a key-value pair. |
memory.search | Search entries by keyword (or vector similarity). |
memory.list | List entries, optionally filtered by key prefix. |
memory.ingest | Chunk a document into overlapping segments and store them. |
These tools do not need to be listed in the agent's spec.tools -- they are injected automatically.
status
phase:Pending,Ready, orError.lastError: description of the most recent error (e.g. unsupported provider, connectivity failure).observedGeneration
Example: examples/resources/memories/research_memory.yaml
AgentPolicy
spec
max_tokens_per_run(int)allowed_models([]string)blocked_tools([]string)apply_mode(string):scopedorglobaltarget_systems([]string)target_tasks([]string)
Defaults and Validation
apply_modedefaults toscoped.apply_modemust bescopedorglobal.
status
phase,lastError,observedGeneration
Example: examples/resources/agent-policies/cost_policy.yaml
AgentRole
spec
description(string)permissions([]string): normalized permission strings.
Defaults and Validation
permissionsare trimmed and deduplicated (case-insensitive).
status
phase,lastError,observedGeneration
Examples: examples/resources/agent-roles/*.yaml
ToolPermission
spec
tool_ref(string): tool name reference.action(string): action name (commonlyinvoke).required_permissions([]string)match_mode(string):alloranyapply_mode(string):globalorscopedtarget_agents([]string): required whenapply_mode=scopedoperation_rules([]object): per-operation-class policy verdicts.operation_class(string):read,write,delete,admin, or*(wildcard). Defaults to*.verdict(string):allow,deny, orapproval_required. Defaults toallow.
Defaults and Validation
tool_refdefaults tometadata.namewhen omitted.actiondefaults toinvoke.match_modedefaults toall.apply_modedefaults toglobal.required_permissionsandtarget_agentsare trimmed and deduplicated.target_agentsmust be non-empty whenapply_mode=scoped.operation_rulesvalues are trimmed and lowercased. Invalidoperation_classorverdictvalues are rejected.- When
operation_rulesis present, the authorizer evaluates the tool'soperation_classesagainst the rules. The most restrictive matching verdict wins (deny>approval_required>allow). - When
operation_rulesis empty, behavior is unchanged (backward-compatible binary allow/deny).
status
phase,lastError,observedGeneration
Examples: examples/resources/tool-permissions/*.yaml
ToolApproval
Captures a pending human/system approval request for a tool invocation that was flagged by a ToolPermission operation_rules verdict of approval_required.
spec
task_ref(string, required): name of the Task resource waiting for approval.tool(string, required): tool name that triggered the approval request.operation_class(string): the operation class that requires approval.agent(string): agent that attempted the tool call.input(string): tool input payload (for audit context).reason(string): human-readable reason for the approval request.ttl(duration string): time-to-live before auto-expiry. Defaults to10m.
status
phase(string):Pending,Approved,Denied,Expired. Defaults toPending.decision(string):approvedordenied.decided_by(string): identity of the approver/denier.decided_at(string): RFC3339 timestamp of the decision.expires_at(string): RFC3339 timestamp when the approval expires.
API Endpoints
POST /v1/tool-approvals-- create an approval request.GET /v1/tool-approvals-- list approval requests (supports namespace and label filters).GET /v1/tool-approvals/{name}-- get a specific approval.DELETE /v1/tool-approvals/{name}-- delete an approval.POST /v1/tool-approvals/{name}/approve-- approve a pending request. Body:{"decided_by": "..."}.POST /v1/tool-approvals/{name}/deny-- deny a pending request. Body:{"decided_by": "..."}.
Task
spec
system(string): targetAgentSystemname.mode(string):run(default) ortemplate.input(map[string]string): task payload.priority(string)max_turns(int, >= 0): required for cyclic graph traversal.retry(object):max_attempts(int)backoff(duration string)
message_retry(object):max_attempts(int)backoff(duration string)max_backoff(duration string)jitter:none,full,equalnon_retryable([]string)
requirements(object):region(string)gpu(bool)model(string)
Defaults and Validation
inputdefaults to{}.prioritydefaults tonormal.modedefaults torun.mode=templatemarks a task as non-executable template for schedules.max_turnsmust be>= 0.retrydefaults:max_attempts->1backoff->0s
message_retrydefaults:max_attempts->retry.max_attemptsbackoff->retry.backoffmax_backoff->24hjitter->full
retry.backoff,message_retry.backoff, andmessage_retry.max_backoffmust parse as durations.
status
Primary fields:
phase:Pending,Running,WaitingApproval,Succeeded,Failed,DeadLetter.lastError,startedAt,completedAt,nextAttemptAt,attemptsoutput,assignedWorker,claimedBy,leaseUntil,lastHeartbeatobservedGeneration
The WaitingApproval phase indicates the task is paused pending a ToolApproval decision. When the linked ToolApproval is approved, the task transitions back to Running. When denied or expired, the task transitions to Failed with an approval_denied or approval_timeout reason.
Observability arrays:
trace[]: detailed execution/tool-call events.history[]: lifecycle transitions.messages[]: message bus records.message_idempotency[]: message idempotency state.join_states[]: fan-in join activation state.
Example: examples/resources/tasks/*.yaml
TaskSchedule
spec
task_ref(string): task template reference (nameornamespace/name).schedule(string): 5-field cron expression.time_zone(string): IANA timezone.suspend(bool): stop triggering whentrue.starting_deadline_seconds(int): max lateness window for catch-up.concurrency_policy(string):forbid(v1).successful_history_limit(int): retained successful run count.failed_history_limit(int): retained failed/deadletter run count.
Defaults and Validation
task_refis required and must benameornamespace/name.scheduleis required and must be a valid 5-field cron.time_zonedefaults toUTC.starting_deadline_secondsdefaults to300.concurrency_policydefaults toforbid.successful_history_limitdefaults to10.failed_history_limitdefaults to3.
status
phase,lastError,observedGenerationlastScheduleTime,lastSuccessfulTime,nextScheduleTimelastTriggeredTask,activeRuns
Example: examples/resources/task-schedules/*.yaml
TaskWebhook
spec
task_ref(string): template task reference (nameornamespace/name).suspend(bool): rejects deliveries whentrue.auth(object):profile(string):generic(default) orgithub.secret_ref(string): required secret reference (nameornamespace/name).signature_header(string)signature_prefix(string)timestamp_header(string): used bygeneric.max_skew_seconds(int): timestamp tolerance forgeneric.
idempotency(object):event_id_header(string): header containing unique delivery id.dedupe_window_seconds(int): dedupe TTL.
payload(object):mode(string):raw(v1 only).input_key(string): generated task input key for raw payload.
Defaults and Validation
task_refis required and must benameornamespace/name.auth.secret_refis required.auth.profiledefaults togeneric; supported values:generic,github.- profile defaults:
generic:signature_header->X-Signaturesignature_prefix->sha256=timestamp_header->X-Timestampidempotency.event_id_header->X-Event-Id
github:signature_header->X-Hub-Signature-256signature_prefix->sha256=idempotency.event_id_header->X-GitHub-Delivery
auth.max_skew_secondsdefaults to300and must be>= 0.idempotency.dedupe_window_secondsmust be>= 0. Defaults to259200(72 hours) forgithubprofile or86400(24 hours) forgenericprofile.payload.modedefaults torawand onlyrawis allowed in v1.payload.input_keydefaults towebhook_payload.
status
phase,lastError,observedGenerationendpointID,endpointPathlastDeliveryTime,lastEventID,lastTriggeredTaskacceptedCount,duplicateCount,rejectedCount
Examples: examples/resources/task-webhooks/*.yaml
McpServer
Represents a connection to an external MCP (Model Context Protocol) server. The McpServer controller discovers tools via tools/list and auto-generates Tool resources (type=mcp) for each.
spec
transport(string): required.stdioorhttp.command(string): stdio transport: command to spawn the MCP server process.args([]string): stdio transport: command arguments.env([]object): stdio transport: environment variables for the child process. Each entry has:name(string): environment variable name.value(string): literal value.secretRef(string): resolve value from a Secret resource. Mutually exclusive withvalue.
endpoint(string): http transport: the MCP server URL.auth(object): http transport: authentication configuration.secretRef(string): secret reference for auth.profile(string):bearerorapi_key_header. Defaults tobearer.
tool_filter(object): optional tool import filtering.include([]string): allowlist of MCP tool names. When set, only listed tools are generated. When empty, all discovered tools are generated.
reconnect(object): reconnection policy.max_attempts(int): max reconnection attempts. Defaults to 3.backoff(duration string): backoff between attempts. Defaults to2s.
Defaults and Validation
transportis required. Must bestdioorhttp.commandis required whentransport=stdio.endpointis required whentransport=http.env[].secretRefandenv[].valueare mutually exclusive.reconnect.max_attemptsdefaults to3.reconnect.backoffdefaults to2s.
status
phase:Pending,Connecting,Ready,Error.discoveredTools([]string): all tool names from the MCP server'stools/listresponse.generatedTools([]string): names of theToolresources actually created.lastSyncedAt(timestamp): last successful tool sync.lastError(string): last error message.
Guide: Connect an MCP Server
Examples: examples/resources/mcp-servers/mcp_server_everything_stdio.yaml, examples/resources/mcp-servers/README.md
Worker
spec
region(string)capabilities.gpu(bool)capabilities.supported_models([]string)max_concurrent_tasks(int)
Defaults and Validation
max_concurrent_tasksdefaults to1when<= 0.
status
phase,lastError,lastHeartbeat,observedGeneration,currentTasks
Example: examples/resources/workers/worker_a.yaml