Skip to content

manifest.yaml Reference

manifest.yaml describes a single capability to the Selu orchestrator. It lives in the root of a capability directory alongside the Dockerfile and optional prompt.md.

manifest.yaml
id: weather-lookup
class: tool
image: ghcr.io/example/weather-lookup:1.0.0
manifest.yaml
id: weather-lookup
class: tool
image: ghcr.io/example/weather-lookup:1.0.0
tools:
- name: get_current_weather
description: Get current weather conditions for a location.
input_schema:
type: object
properties:
location:
type: string
description: City name or coordinates
units:
type: string
description: "Unit system: metric or imperial"
default: "metric"
required: ["location"]
recommended_policy: allow
credentials:
- name: WEATHER_API_KEY
scope: system
required: true
description: API key for the weather service
resources:
max_memory_mb: 128
max_cpu_fraction: 0.5
manifest.yaml
id: file-manager
class: tool
image: ghcr.io/example/file-manager:2.0.0
tool_source: dynamic
discovery_tool_name: list_available_tools
credentials:
- name: CLOUD_STORAGE_TOKEN
scope: user
required: false
description: Optional token for cloud storage integration
resources:
max_memory_mb: 256
max_cpu_fraction: 0.75
FieldTypeRequiredDefaultDescription
idstringYesUnique identifier (lowercase, hyphens).
classstringNo"tool""tool" or "environment".
imagestringYesDocker image that implements this capability.
tool_sourcestringNo"manifest"How tools are defined: "manifest" or "dynamic".
discovery_tool_namestringNo"list_tools"Name of the tool used for dynamic discovery.
toolslistNo[]Static tool definitions (only when tool_source is "manifest").
networkobjectNoSee belowNetwork access configuration.
filesystemstringNo"none"Filesystem access policy.
credentialslistNo[]Required credentials and secrets.
resourcesobjectNoSee belowContainer resource limits.

Selu supports two methods for defining what tools a capability provides:

Tools are declared directly in the manifest.yaml file. This is the traditional approach and remains the default.

Tools are discovered at runtime by invoking a special discovery tool on the capability container. This allows capabilities to:

  • Adapt their available tools based on runtime conditions
  • Provide different tools based on available credentials
  • Update their tool set without requiring a manifest change

When using dynamic discovery, Selu will:

  1. Start your capability container
  2. Call the discovery tool (default name: list_tools)
  3. Parse the returned tool definitions
  4. Cache the results and sync them periodically

The discovery tool must return a JSON array of tool definitions:

[
{
"name": "read_file",
"description": "Read contents of a file",
"input_schema": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "File path"}
},
"required": ["path"]
},
"recommended_policy": "ask"
}
]

Each entry describes one callable function that agents can invoke.

FieldTypeRequiredDescription
namestringYesTool name used in gRPC InvokeRequest.tool_name.
descriptionstringYesSent to agents to explain what the tool does.
input_schemaobjectYesJSON Schema defining the tool’s parameters.
requires_confirmationboolNoLegacy field — use recommended_policy instead.
recommended_policystringNoRecommended security policy: "allow", "ask", or "block".
terminal_on_successboolNoExit the tool loop after a successful invocation. Default false.
FieldTypeDefaultDescription
modestring"none"Network access mode: "none", "allowlist", or "any".
hostsarray[]Allowed hosts for allowlist mode (format: "host:port").

Network hosts support wildcard matching for subdomains:

  • "api.example.com:443" — matches exactly api.example.com on port 443
  • "*.example.com:443" — matches any subdomain like cdn.example.com or api.example.com
  • "*.example.com" — matches subdomains on any port
ValueDescription
"none"Read-only root filesystem, no persistent storage.
"temp"Writable /tmp directory (cleared on container restart).
"workspace"Named Docker volume mounted at /workspace (environment class only).
FieldTypeRequiredDefaultDescription
namestringYesEnvironment variable name.
scopestringYes"system" (shared) or "user" (per-user).
credential_typestringNo"secret"Type of credential (currently only "secret").
requiredboolNotrueWhether this credential is mandatory.
descriptionstringNo""Human-readable explanation for users.
FieldTypeDefaultDescription
max_memory_mbinteger128Memory limit in megabytes.
max_cpu_fractionnumber0.5CPU limit in cores (0.5 = half a core).
max_cpu_secondsinteger30Maximum CPU time per tool invocation.
pids_limitinteger64Maximum processes/threads.

For capabilities using tool_source: dynamic, you must implement a discovery tool that returns the current set of available tools.

The discovery tool is called like any other tool, but it should return a JSON array describing all available tools:

server.py
def invoke(self, request, context):
if request.tool_name == "list_tools":
# Return available tools based on current state
tools = []
# Always available
tools.append({
"name": "basic_operation",
"description": "Performs a basic operation",
"input_schema": {
"type": "object",
"properties": {
"input": {"type": "string"}
},
"required": ["input"]
},
"recommended_policy": "allow"
})
# Only available if credential is configured
if os.getenv("PREMIUM_API_KEY"):
tools.append({
"name": "premium_feature",
"description": "Access premium features",
"input_schema": {
"type": "object",
"properties": {
"query": {"type": "string"}
}
},
"required": ["query"]
},
"recommended_policy": "ask"
})
return pb2.InvokeResponse(
result=json.dumps(tools),
success=True
)

Selu automatically syncs dynamic tools:

  • At startup — Best-effort sync for all loaded agents
  • During install/update — Tools are discovered as part of the installation process
  • During setup — Fresh discovery before presenting tool policies to users

When tools change between syncs:

  • Added tools get the global default policy (from recommended_policy or "block")
  • Removed tools are deleted from policy tables and discovered cache
  • Modified tools update their cached definitions

If discovery fails, Selu keeps the previous cached tools and logs an error.

Common validation errors:

  • Dynamic + static conflicttool_source: dynamic requires tools: []
  • Missing discovery tool — Dynamic capabilities must implement the discovery tool
  • Invalid tool schemas — Both static and discovered tools must have valid JSON Schema
  • Network host format — Hosts must be in "hostname:port" format

Use static tools when:

  • Your capability provides a fixed set of tools
  • Tool definitions don’t change based on runtime conditions
  • You want simpler deployment and debugging

Use dynamic tools when:

  • Available tools depend on configured credentials
  • You want to add/remove tools without updating the manifest
  • Tools are determined by external state or APIs