* docs: teach agents to pass a resource as $res:<path> in run arguments Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XjRARL7JA7xm772iJP4mJk * docs: extend run-argument rule to in-editor chats, fix run-as wording Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XjRARL7JA7xm772iJP4mJk * docs: tighten resource run-argument rule after review - Drop the false rationale that "$var:" only works inside a resource value from the write_variable description and its runtime rejection message; keep the rule (a variable cannot reference itself). - MCP resource-argument description: the title fallback renders "No title", so say the title is only a label rather than that it can be empty. Guard the real-newline fix with asserts in the existing enrichment test. - Eval: assert the full "$res:f/evals/global/github_main" value as one prefix so a wrong path with a right prefix fails. - resources.md: narrow "a trigger's payload" to its configured static args. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XjRARL7JA7xm772iJP4mJk * docs: scope the run-argument rule to global chat, add an exact eval matcher The ai_evals A/B on the two in-editor modes showed no effect: script mode sonnet 5/5 both with and without the description, flow mode sonnet 5/5 and haiku 5/5 on the baseline alone. A flow's input schema already carries `format: resource-<type>`, so those modes have a signal global mode does not give. Revert both files to keep the tool schemas free of a description that buys nothing per iteration; global mode keeps it, where haiku goes 0/5 -> 5/5. Add `stringEqualsAnyOf` to toolCallArgs and use it for the resource reference: nothing in the eval resolves the value, so a prefix match accepted a near-miss path like `$res:f/evals/global/github_main_backup`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XjRARL7JA7xm772iJP4mJk * docs: address cubic review — CLI wording, mock resource getter - `-d --data` help on all four run/preview commands: give $res: and $var: their own clauses instead of a parenthetical that read as if a resource were a kind of variable. - Mock backend: `getBenchmarkResource` now resolves AI-provider seeds as well as plain ones, so it agrees with `existsResource` and `listResource` — both report either kind, and a case that listed a resource and then read it by path got a row it could not fetch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XjRARL7JA7xm772iJP4mJk --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
5.7 KiB
Windmill Resources
Resources store credentials and configuration for external services.
File Format
Resource files use the pattern: {path}.resource.json
Example: f/databases/postgres_prod.resource.json
Resource Structure
{
"value": {
"host": "db.example.com",
"port": 5432,
"user": "admin",
"password": "$var:g/all/db_password",
"dbname": "production"
},
"description": "Production PostgreSQL database",
"resource_type": "postgresql"
}
Required Fields
value- Object containing the resource configurationresource_type- Name of the resource type (e.g., "postgresql", "slack")
Variable References
Reference variables in resource values:
{
"value": {
"api_key": "$var:g/all/api_key",
"secret": "$var:u/admin/secret"
}
}
Reference formats:
$var:g/all/name- Global variable$var:u/username/name- User variable$var:f/folder/name- Folder variable
Resource References
Reference other resources:
{
"value": {
"database": "$res:f/databases/postgres"
}
}
Passing a Resource or Variable as a Run Argument
A script or flow argument typed as a resource (schema format: resource-<type>) is passed as
the bare string $res:<path> — the whole argument value. Same for a variable, with
$var:<path>. This applies everywhere job arguments are supplied: wmill script run/preview,
wmill flow run/preview, the runScriptByPath / runFlowByPath API, a schedule's args, a
trigger's configured static args.
{
"db": "$res:f/databases/postgres_prod",
"api_token": "$var:g/all/api_token"
}
The reference is resolved when the job runs, under the job's run-as identity — the caller for an ordinary run, but the configured principal for a schedule, a trigger, or a runnable set to run on behalf of someone else. The run fails if that identity cannot read the referenced resource or variable.
Never wrap it in an object. The resolver only rewrites a JSON value that is a string
starting with $res: / $var:; keys are never inspected. These are all wrong and are passed
through to the script unchanged:
{ "db": { "$res": "f/databases/postgres_prod" } }
{ "db": { "resource": "f/databases/postgres_prod" } }
{ "db": "f/databases/postgres_prod" }
The string may sit anywhere a string can — a top-level argument, a nested object field
({ "gh_auth": { "token": "$var:g/all/gh_token" } }), or an array element (array elements are
walked only while nested at most two levels deep, and only for arrays of at most 1000 items).
The prefix must be on the string itself.
Common Resource Types
PostgreSQL
{
"resource_type": "postgresql",
"value": {
"host": "localhost",
"port": 5432,
"user": "postgres",
"password": "$var:g/all/pg_password",
"dbname": "windmill",
"sslmode": "prefer"
}
}
MySQL
{
"resource_type": "mysql",
"value": {
"host": "localhost",
"port": 3306,
"user": "root",
"password": "$var:g/all/mysql_password",
"database": "myapp"
}
}
Slack
{
"resource_type": "slack",
"value": {
"token": "$var:g/all/slack_token"
}
}
AWS S3
{
"resource_type": "s3",
"value": {
"bucket": "my-bucket",
"region": "us-east-1",
"accessKeyId": "$var:g/all/aws_access_key",
"secretAccessKey": "$var:g/all/aws_secret_key"
}
}
HTTP/API
{
"resource_type": "http",
"value": {
"baseUrl": "https://api.example.com",
"headers": {
"Authorization": "Bearer $var:g/all/api_token"
}
}
}
Kafka
{
"resource_type": "kafka",
"value": {
"brokers": "broker1:9092,broker2:9092",
"sasl_mechanism": "PLAIN",
"security_protocol": "SASL_SSL",
"username": "$var:g/all/kafka_user",
"password": "$var:g/all/kafka_password"
}
}
NATS
{
"resource_type": "nats",
"value": {
"servers": ["nats://localhost:4222"],
"user": "$var:g/all/nats_user",
"password": "$var:g/all/nats_password"
}
}
MQTT
{
"resource_type": "mqtt",
"value": {
"host": "mqtt.example.com",
"port": 8883,
"username": "$var:g/all/mqtt_user",
"password": "$var:g/all/mqtt_password",
"tls": true
}
}
Custom Resource Types
Create custom resource types with JSON Schema:
{
"name": "custom_api",
"schema": {
"type": "object",
"properties": {
"base_url": {"type": "string", "format": "uri"},
"api_key": {"type": "string"},
"timeout": {"type": "integer", "default": 30}
},
"required": ["base_url", "api_key"]
},
"description": "Custom API connection"
}
Save as: custom_api.resource-type.json
OAuth Resources
OAuth resources are managed through the Windmill UI and marked:
{
"is_oauth": true,
"account": 123
}
OAuth tokens are automatically refreshed by Windmill.
Using Resources in Scripts
TypeScript (Bun/Deno)
export async function main(db: RT.Postgresql) {
// db contains the resource values
const { host, port, user, password, dbname } = db;
}
Python
class postgresql(TypedDict):
host: str
port: int
user: str
password: str
dbname: str
def main(db: postgresql):
# db contains the resource values
pass
CLI Commands
# List resources
wmill resource list
# List resource types with schemas
wmill resource-type list --schema
# Get specific resource type schema
wmill resource-type get postgresql
# Deploy resources to the workspace — destructive to remote state, so only run when
# the user explicitly asks to deploy/publish/push. Depending on how the repo is wired,
# deploy via `git push` or `wmill sync push` (see the Deploying section in AGENTS.wmill.md).
wmill sync push