Capability YAML
capability.yaml is the agent-side source of truth. It defines what can be called, what input is accepted, what SQL is executed, and which output columns may leave the database boundary.
Structure
service:
title: Example CRM Capabilities
version: 0.1.0
description: Agent-defined capabilities for a legacy CRM database.
runtime:
max_concurrent_requests: 16
gateway:
url: "wss://customer-abc.example.com/ws/agent"
agent_private_key: "base64url-ed25519-private-key"
database:
driver: postgres
host: localhost
port: 5432
name: legacy_db
user: readonly_user
password: ""
tls:
mode: verify-full
ca_file: /etc/onprest/db-ca.pem
cert_file: /etc/onprest/db-client.pem
key_file: /etc/onprest/db-client-key.pem
server_name: db.internal.example.com
logging:
max_size: 10MB
max_files: 3
defaults:
readonly: true
timeout: 30s
max_rows: 1000
max_bytes: 1MB
capabilities:
get_customer:
description: "Fetch one customer by id"
sql: select id, name, email from customers where id = :customer_id
params:
customer_id:
type: integer
required: true
minimum: 1
description: "Customer ID"
policy:
readonly: true
timeout: 5s
max_rows: 1
max_bytes: 256KB
expose_in_openapi: true
result:
id:
type: integer
description: "Customer ID"
name:
type: string
description: "Customer name"
email:
type: string
description: "Email address"Top-Level Sections
| Section | Purpose |
|---|---|
service | OpenAPI info metadata |
runtime | agent request execution limits |
gateway | gateway WebSocket URL and agent private key |
database | DB driver and connection settings |
logging | agent local detail log rotation settings |
defaults | default policy values used by capabilities |
capabilities | externally callable operations |
Supported database drivers are postgres, mysql, sqlserver, and oracle.
Capability names must match ^[a-zA-Z][a-zA-Z0-9_.-]{0,127}$.
Descriptions
description fields are optional but recommended. They are public metadata used to make generated OpenAPI and MCP tools understandable to API users and AI agents.
Descriptions do not grant permissions, change validation, affect SQL execution, or bypass policy / result enforcement. Security behavior is defined by capability names, API key authorization, params validation, policy, SQL, and result allow-lists.
| Location | Required | Purpose |
|---|---|---|
service.description | No | OpenAPI service-level documentation |
capabilities.<name>.description | No | Capability / operation / MCP tool description |
params.<name>.description | No | Public input parameter documentation |
result.<column>.description | No | Public output field documentation |
For AI/MCP use, write descriptions as stable business-facing contract text. Do not put secrets, internal-only incident detail, DB credentials, or sensitive operational notes in descriptions because they can appear in OpenAPI and MCP metadata.
Service
service provides the OpenAPI info metadata for the generated spec. All fields are optional.
| Field | Required | Default | Description |
|---|---|---|---|
title | No | Onprest Agent | OpenAPI service title |
version | No | 0.1.0 | OpenAPI service version |
description | No | empty | OpenAPI service-level documentation |
When title or version is empty, the agent fills in the default shown above at startup.
Runtime
| Field | Required | Default | Description |
|---|---|---|---|
max_concurrent_requests | No | 16 | Maximum capability requests executed concurrently on one gateway connection |
The value must be a positive integer. The agent has the same number of bounded waiting slots in addition to the running slots. Waiting requests do not reach the database early, and the WebSocket reader continues processing ping/pong while the execution limit is saturated. If both running and waiting slots are full, the request fails with AGENT_BUSY instead of growing memory without a bound. One response writer sends WebSocket frames in sequence. Once a frame write starts, it must finish within five seconds; this is not a query timeout or a limit on time spent waiting for the writer. Higher values can increase throughput but also increase simultaneous database work and connection-pool demand. Unknown YAML fields and multiple YAML documents are rejected at startup so a misspelled limit cannot silently fall back to 16. Restart the agent to apply a change.
Gateway
| Field | Required | Description |
|---|---|---|
url | Yes | Gateway WebSocket URL, usually ending in /ws/agent |
agent_private_key | Yes | base64url Ed25519 private key generated by onprest-gateway create-agent-secret |
allow_insecure_non_loopback_ws | No | Development-only acknowledgement for non-loopback ws://; defaults to false and must remain false in production |
url must use the exact /ws/agent path without credentials, a query, or a fragment. Non-loopback addresses require wss:// unless the development-only insecure acknowledgement is explicitly enabled. Loopback ws://localhost, ws://127.0.0.1, and ws://[::1] remain available for local development.
Database
| Field | Required | Description |
|---|---|---|
driver | Yes | postgres, mysql, sqlserver, or oracle |
host | Yes | DB hostname or IP address |
port | Yes | DB port |
name | Yes | Database, service, or schema name used by the driver |
user | Yes | DB username |
password | No | DB password; keep this only on the agent side |
tls.mode | No | TLS mode described below; defaults to disable |
tls.ca_file | No | PEM CA certificate used to verify the DB server |
tls.cert_file | No | PostgreSQL PEM client certificate for mutual TLS |
tls.key_file | No | PostgreSQL PEM client private key; required together with cert_file |
tls.server_name | No | SQL Server certificate hostname override; otherwise host is verified |
TLS support is driver-specific:
| Driver | Supported tls.mode | Behavior |
|---|---|---|
| PostgreSQL | disable, require, verify-ca, verify-full | Uses lib/pq TLS settings. Set ca_file for a private CA; client certificate and key are optional but must be supplied together. |
| SQL Server | disable, require, verify-full | require encrypts while trusting the presented server certificate. verify-full verifies the certificate trust chain plus server_name or host; set ca_file for a private CA. |
| MySQL / Oracle | disable only | Non-disabled TLS is rejected at startup; this avoids silently pretending that the generated connection is verified. |
Do not set TLS CA, certificate, key, or server-name fields when mode: disable. cert_file and key_file are PostgreSQL-only; server_name is SQL Server-only. Prefer a verified mode on networks where the database connection can be intercepted.
Logging
| Field | Default | Description |
|---|---|---|
max_size | 10MB | Size threshold for rotating the local detail log |
max_files | 3 | Number of rotated files to retain |
max_size accepts a non-negative integer followed by an optional B, KB, MB, or GB suffix, such as 10MB. A bare integer is treated as bytes. Fractions, unknown suffixes, trailing text, and values that overflow int64 are rejected.
The local detail log path is the agent executable path plus .log, for example onprest-agent.log.
Defaults
defaults is optional. It supplies policy defaults for capabilities, and each capability’s own policy values take precedence.
If neither defaults nor capability policy sets a value, the implementation defaults are:
| Field | Default |
|---|---|
readonly | true |
timeout | 5s |
max_rows | 100 |
max_bytes | 1MB |
expose_in_openapi | true |
Capabilities
Each entry under capabilities defines one externally callable operation. At least one capability is required; the agent rejects a file with no capabilities at startup.
| Field | Required | Description |
|---|---|---|
description | No | Public operation text used by OpenAPI and MCP tools |
sql | Yes | SQL executed by the agent after validation |
params | No | Input contract; unknown provided params are rejected |
policy | No | Execution limits; missing values use defaults or implementation defaults |
result | No | Output allow-list; omitted result means row object fields are not returned |
Params
params defines the input contract.
| Field | Description |
|---|---|
type | string, integer, number, or boolean |
required | whether the caller must provide the value |
default | value applied when omitted |
enum | allowed values |
minimum / maximum | numeric bounds |
minLength / maxLength | string length bounds |
pattern | regular expression |
format | one of email, uuid, date, date-time, uri |
description | public documentation text |
Unknown params are rejected.
minimum and maximum are integer-valued bounds and apply to integer and number params. JSON integer tokens are converted exactly through signed 64-bit integers, including values above JavaScript’s 2^53 precision boundary; fractional and int64-overflow values are rejected. number also rejects non-finite values.
format accepts only the five values listed above; any other value is rejected at startup. minLength and maxLength must be 0 or greater, and minLength must not exceed maxLength.
Policy
policy limits execution.
| Field | Description |
|---|---|
readonly | true accepts one statement beginning with SELECT, including nested SELECT subqueries |
timeout | execution timeout, such as 5s |
max_rows | maximum rows returned |
max_bytes | maximum response size, such as 256KB |
expose_in_openapi | whether to include the capability in OpenAPI and MCP tools/list |
Use read-only DB users for read capabilities. YAML policy is an application guard; DB privileges should still enforce least privilege.
timeout accepts a Go duration string such as 5s or 500ms. max_bytes uses the same exact non-negative integer byte-size grammar as logging.max_size.
When readonly is true, startup lint rejects another statement after the first, such as SELECT 1; UPDATE customers SET .... One trailing semicolon is allowed. Quote scanning follows the configured driver: ordinary SQL strings use doubled quotes and never treat backslash as a quote escape; PostgreSQL explicit E'...' strings support backslash escaping; PostgreSQL dollar quotes, SQL Server bracket identifiers, MySQL backticks, and Oracle alternative q'...' quotes are recognized. This conservative rule also prevents SELECT '\'; UPDATE ... from bypassing lint when a server or SQL mode treats the backslash literally. Statements beginning with WITH are rejected, including read-only CTEs. timeout, max_rows, and max_bytes are enforced during capability execution.
Result Allow-List
result is the output allow-list.
- Columns not listed in
resultare removed from the response. - If SQL does not return a column listed in
result, execution fails. - If
resultis omitted, row object fields are not returned. - Even with
SELECT *, only result-listed columns can leave the agent boundary.
This is the final guard that prevents accidental exposure of extra columns.
Supported result column types are string, integer, number, and boolean.