mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-14 00:02:55 +00:00
* 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>
280 lines
5.7 KiB
Markdown
280 lines
5.7 KiB
Markdown
# 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
|
|
|
|
```json
|
|
{
|
|
"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 configuration
|
|
- `resource_type` - Name of the resource type (e.g., "postgresql", "slack")
|
|
|
|
## Variable References
|
|
|
|
Reference variables in resource values:
|
|
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
```json
|
|
{
|
|
"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.
|
|
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
```json
|
|
{ "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
|
|
```json
|
|
{
|
|
"resource_type": "postgresql",
|
|
"value": {
|
|
"host": "localhost",
|
|
"port": 5432,
|
|
"user": "postgres",
|
|
"password": "$var:g/all/pg_password",
|
|
"dbname": "windmill",
|
|
"sslmode": "prefer"
|
|
}
|
|
}
|
|
```
|
|
|
|
### MySQL
|
|
```json
|
|
{
|
|
"resource_type": "mysql",
|
|
"value": {
|
|
"host": "localhost",
|
|
"port": 3306,
|
|
"user": "root",
|
|
"password": "$var:g/all/mysql_password",
|
|
"database": "myapp"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Slack
|
|
```json
|
|
{
|
|
"resource_type": "slack",
|
|
"value": {
|
|
"token": "$var:g/all/slack_token"
|
|
}
|
|
}
|
|
```
|
|
|
|
### AWS S3
|
|
```json
|
|
{
|
|
"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
|
|
```json
|
|
{
|
|
"resource_type": "http",
|
|
"value": {
|
|
"baseUrl": "https://api.example.com",
|
|
"headers": {
|
|
"Authorization": "Bearer $var:g/all/api_token"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Kafka
|
|
```json
|
|
{
|
|
"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
|
|
```json
|
|
{
|
|
"resource_type": "nats",
|
|
"value": {
|
|
"servers": ["nats://localhost:4222"],
|
|
"user": "$var:g/all/nats_user",
|
|
"password": "$var:g/all/nats_password"
|
|
}
|
|
}
|
|
```
|
|
|
|
### MQTT
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
```json
|
|
{
|
|
"is_oauth": true,
|
|
"account": 123
|
|
}
|
|
```
|
|
|
|
OAuth tokens are automatically refreshed by Windmill.
|
|
|
|
## Using Resources in Scripts
|
|
|
|
### TypeScript (Bun/Deno)
|
|
```typescript
|
|
export async function main(db: RT.Postgresql) {
|
|
// db contains the resource values
|
|
const { host, port, user, password, dbname } = db;
|
|
}
|
|
```
|
|
|
|
### Python
|
|
```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
|
|
|
|
```bash
|
|
# 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
|
|
```
|