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.
Minimal example
Section titled “Minimal example”id: weather-lookupclass: toolimage: ghcr.io/example/weather-lookup:1.0.0Static tools example
Section titled “Static tools example”id: weather-lookupclass: toolimage: 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.5Dynamic tools example
Section titled “Dynamic tools example”id: file-managerclass: toolimage: ghcr.io/example/file-manager:2.0.0tool_source: dynamicdiscovery_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.75Schema
Section titled “Schema”Top-level fields
Section titled “Top-level fields”| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | string | Yes | Unique identifier (lowercase, hyphens). | |
class | string | No | "tool" | "tool" or "environment". |
image | string | Yes | Docker image that implements this capability. | |
tool_source | string | No | "manifest" | How tools are defined: "manifest" or "dynamic". |
discovery_tool_name | string | No | "list_tools" | Name of the tool used for dynamic discovery. |
tools | list | No | [] | Static tool definitions (only when tool_source is "manifest"). |
network | object | No | See below | Network access configuration. |
filesystem | string | No | "none" | Filesystem access policy. |
credentials | list | No | [] | Required credentials and secrets. |
resources | object | No | See below | Container resource limits. |
Tool sources
Section titled “Tool sources”Selu supports two methods for defining what tools a capability provides:
Static tools (tool_source: manifest)
Section titled “Static tools (tool_source: manifest)”Tools are declared directly in the manifest.yaml file. This is the traditional approach and remains the default.
Dynamic tools (tool_source: dynamic)
Section titled “Dynamic tools (tool_source: dynamic)”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:
- Start your capability container
- Call the discovery tool (default name:
list_tools) - Parse the returned tool definitions
- 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" }]tools[*] (static mode only)
Section titled “tools[*] (static mode only)”Each entry describes one callable function that agents can invoke.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Tool name used in gRPC InvokeRequest.tool_name. |
description | string | Yes | Sent to agents to explain what the tool does. |
input_schema | object | Yes | JSON Schema defining the tool’s parameters. |
requires_confirmation | bool | No | Legacy field — use recommended_policy instead. |
recommended_policy | string | No | Recommended security policy: "allow", "ask", or "block". |
terminal_on_success | bool | No | Exit the tool loop after a successful invocation. Default false. |
network
Section titled “network”| Field | Type | Default | Description |
|---|---|---|---|
mode | string | "none" | Network access mode: "none", "allowlist", or "any". |
hosts | array | [] | Allowed hosts for allowlist mode (format: "host:port"). |
Network hosts support wildcard matching for subdomains:
"api.example.com:443"— matches exactlyapi.example.comon port 443"*.example.com:443"— matches any subdomain likecdn.example.comorapi.example.com"*.example.com"— matches subdomains on any port
filesystem
Section titled “filesystem”| Value | Description |
|---|---|
"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). |
credentials[*]
Section titled “credentials[*]”| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | Environment variable name. | |
scope | string | Yes | "system" (shared) or "user" (per-user). | |
credential_type | string | No | "secret" | Type of credential (currently only "secret"). |
required | bool | No | true | Whether this credential is mandatory. |
description | string | No | "" | Human-readable explanation for users. |
resources
Section titled “resources”| Field | Type | Default | Description |
|---|---|---|---|
max_memory_mb | integer | 128 | Memory limit in megabytes. |
max_cpu_fraction | number | 0.5 | CPU limit in cores (0.5 = half a core). |
max_cpu_seconds | integer | 30 | Maximum CPU time per tool invocation. |
pids_limit | integer | 64 | Maximum processes/threads. |
Dynamic tool discovery
Section titled “Dynamic tool discovery”For capabilities using tool_source: dynamic, you must implement a discovery tool that returns the current set of available tools.
Discovery tool interface
Section titled “Discovery tool interface”The discovery tool is called like any other tool, but it should return a JSON array describing all available tools:
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 )Sync behavior
Section titled “Sync behavior”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_policyor"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.
Validation
Section titled “Validation”Common validation errors:
- Dynamic + static conflict —
tool_source: dynamicrequirestools: [] - 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
Choosing static vs. dynamic
Section titled “Choosing static vs. dynamic”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
Next steps
Section titled “Next steps”- gRPC Interface — Learn the protocol details for implementing capability servers.
- Container Guidelines — Security and resource requirements for Docker images.
- Built-in Tools Reference — Tools available to all agents by default.