mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-17 16:02:25 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
062092eaf5 |
@@ -7,6 +7,7 @@ export interface SkillMetadata {
|
||||
}
|
||||
|
||||
export const SKILLS: SkillMetadata[] = [
|
||||
{ name: "write-script-ansible", description: "MUST use when writing Ansible playbooks.", languageKey: "ansible" },
|
||||
{ name: "write-script-bash", description: "MUST use when writing Bash scripts.", languageKey: "bash" },
|
||||
{ name: "write-script-bigquery", description: "MUST use when writing BigQuery queries.", languageKey: "bigquery" },
|
||||
{ name: "write-script-bun", description: "MUST use when writing Bun/TypeScript scripts.", languageKey: "bun" },
|
||||
@@ -38,6 +39,151 @@ export const SKILLS: SkillMetadata[] = [
|
||||
|
||||
// Skill content for each skill (loaded inline for bundling)
|
||||
export const SKILL_CONTENT: Record<string, string> = {
|
||||
"write-script-ansible": `---
|
||||
name: write-script-ansible
|
||||
description: MUST use when writing Ansible playbooks.
|
||||
---
|
||||
|
||||
## CLI Commands
|
||||
|
||||
Place scripts in a folder.
|
||||
|
||||
After writing, tell the user which command fits what they want to do:
|
||||
|
||||
- \`wmill script preview <script_path>\` — **default when iterating on a local script.** Runs the local file without deploying.
|
||||
- \`wmill script run <path>\` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
|
||||
- \`wmill generate-metadata\` — regenerate the local \`.script.yaml\` (input schema) and \`.lock\` (resolved dependencies) for scripts you changed, and refresh their content hashes in \`wmill-lock.yaml\`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
|
||||
- \`wmill sync push\` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
|
||||
|
||||
### Preview vs run — choose by intent, not habit
|
||||
|
||||
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use \`script preview\`. Do NOT push the script to then \`script run\` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
||||
|
||||
Only use \`script run\` when:
|
||||
- The user explicitly says "run the deployed version" / "run what's on the server".
|
||||
- There is no local script being edited (you're just invoking an existing script).
|
||||
|
||||
Only use \`sync push\` when:
|
||||
- The user explicitly asks to deploy, publish, push, or ship.
|
||||
- The preview has already validated the change and the user wants it in the workspace.
|
||||
|
||||
### Keep metadata in sync after editing
|
||||
|
||||
\`wmill-lock.yaml\` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing \`main\`'s arguments** — invalidates that hash and leaves the \`.lock\`, the \`.script.yaml\` input schema, and the hash row out of date. Run \`wmill generate-metadata\` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by \`.script.yaml\`), and \`wmill-lock.yaml\` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
|
||||
|
||||
This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's \`AGENTS.md\` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated \`.lock\` / \`.script.lock\` files and tell the user which dependency versions changed (e.g. \`requests 2.31.0 → 2.32.0\`), so they can catch an unwanted bump before deploying — even under \`Metadata: auto\`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
|
||||
|
||||
With no path argument, \`generate-metadata\` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run \`wmill generate-metadata --dry-run\` — it lists each stale item with a reason (\`content changed\` or \`depends on <path>\`) without changing anything — then narrow with a path argument (\`wmill generate-metadata f/foo\`) or \`--strict-folder-boundaries\`.
|
||||
|
||||
If the on-disk \`.lock\` and \`.script.yaml\` are already correct and only \`wmill-lock.yaml\` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use \`wmill generate-metadata rehash\` — it re-records hashes from disk with no backend round-trip and no dependency changes.
|
||||
|
||||
### After writing — offer to test, don't wait passively
|
||||
|
||||
If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run \`wmill script preview\` with sample args?"). Do not present a multi-option menu.
|
||||
|
||||
If the user already asked to test/run/try the script in their original request, skip the offer and just execute \`wmill script preview <path> -d '<args>'\` directly — pick plausible args from the script's declared parameters. The shape varies by language: \`main(...)\` for code languages, the SQL dialect's own placeholder syntax (\`$1\` for PostgreSQL, \`?\` for MySQL/Snowflake, \`@P1\` for MSSQL, \`@name\` for BigQuery, etc.), positional \`$1\`, \`$2\`, … for Bash, \`param(...)\` for PowerShell.
|
||||
|
||||
\`wmill script preview\` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). \`wmill generate-metadata\` does not deploy either — it only writes local files (locks, schemas, hashes) — but offer it before running (or run automatically if the project's \`AGENTS.md\` opts in), per "Keep metadata in sync" above. Only \`wmill sync push\` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
|
||||
|
||||
For a **visual** open-the-script-in-the-dev-page preview (rather than \`script preview\`'s run-and-print-result), use the \`preview\` skill.
|
||||
|
||||
Use \`wmill resource-type list --schema\` to discover available resource types.
|
||||
|
||||
# Ansible
|
||||
|
||||
A Windmill Ansible script is a YAML document with two parts separated by a \`---\` line:
|
||||
|
||||
1. A **Windmill header** that declares the script's inputs, dependencies, inventory, file resources and options.
|
||||
2. One or more **Ansible plays** (the standard playbook content) executed with \`ansible-playbook\`.
|
||||
|
||||
## Structure
|
||||
|
||||
\`\`\`yaml
|
||||
---
|
||||
inventory:
|
||||
- resource_type: ansible_inventory
|
||||
# Pin an inventory by hardcoding the resource path (optional):
|
||||
# resource: u/user/your_inventory
|
||||
|
||||
options:
|
||||
- verbosity: vvv
|
||||
|
||||
# File resources/variables are written to their relative \`target\` location
|
||||
# before the playbook runs:
|
||||
# files:
|
||||
# - resource: u/user/fabulous_jinja_template
|
||||
# target: ./config_template.j2
|
||||
# - variable: u/user/ssh_key
|
||||
# target: ./ssh_key
|
||||
# mode: '0600'
|
||||
|
||||
# Inputs of the Windmill script. Each key becomes an Ansible variable usable
|
||||
# with {{ var_name }}. The JSON Schema is inferred from these declarations.
|
||||
extra_vars:
|
||||
world_qualifier:
|
||||
type: string
|
||||
|
||||
# If using Ansible Vault:
|
||||
# vault_password: u/user/ansible_vault_password
|
||||
|
||||
dependencies:
|
||||
galaxy:
|
||||
collections:
|
||||
- name: community.general
|
||||
roles:
|
||||
python:
|
||||
- jmespath
|
||||
---
|
||||
- name: Echo
|
||||
hosts: 127.0.0.1
|
||||
connection: local
|
||||
tasks:
|
||||
- name: Print debug message
|
||||
debug:
|
||||
msg: "Hello, {{ world_qualifier }} world!"
|
||||
\`\`\`
|
||||
|
||||
## Inputs (\`extra_vars\`)
|
||||
|
||||
- Each entry under \`extra_vars\` declares a Windmill script argument and is passed to the playbook as an Ansible variable (\`--extra-vars\`).
|
||||
- Reference them in tasks with Jinja: \`{{ world_qualifier }}\`.
|
||||
- Supported \`type\` values: \`string\`, \`number\`, \`boolean\`, \`object\` (and nested schemas). This is what generates the script's input form.
|
||||
|
||||
## Inventory
|
||||
|
||||
- \`inventory:\` with \`resource_type: ansible_inventory\` lets the user select an inventory resource at runtime; add \`resource: u/user/...\` to pin one.
|
||||
- \`dynamic_inventory\` entries reference a \`name\` (e.g. \`hcloud.yml\`) for cloud/dynamic inventories.
|
||||
|
||||
## File resources and variables
|
||||
|
||||
Under \`files:\`, materialize Windmill resources or variables onto disk before the run:
|
||||
- \`resource: <path>\` or \`variable: <path>\` — the Windmill object to fetch.
|
||||
- \`target: ./relative/path\` — where to write it (relative paths only).
|
||||
- \`mode: '0600'\` — optional octal file permission (useful for SSH keys).
|
||||
|
||||
## Dependencies
|
||||
|
||||
- \`dependencies.galaxy.collections\` / \`dependencies.galaxy.roles\` — installed via \`ansible-galaxy\`.
|
||||
- \`dependencies.python\` — pip packages available to Ansible modules (e.g. \`jmespath\` for the \`json_query\` filter).
|
||||
|
||||
## Output
|
||||
|
||||
The script result is read from a \`result.json\` file in the job directory. Write it from a task, e.g.:
|
||||
|
||||
\`\`\`yaml
|
||||
- name: Write result
|
||||
delegate_to: localhost
|
||||
copy:
|
||||
content: "{{ my_result | to_json }}"
|
||||
dest: result.json
|
||||
\`\`\`
|
||||
|
||||
## Notes
|
||||
|
||||
- The header keys (\`inventory\`, \`extra_vars\`, \`files\`, \`options\`, \`vault_password\`, \`dependencies\`) are Windmill-specific — do not confuse them with Ansible's own keys.
|
||||
- Use \`hosts: 127.0.0.1\` with \`connection: local\` for local tasks; otherwise rely on the selected inventory.
|
||||
- Keep the \`---\` separator between the Windmill header and the plays.
|
||||
`,
|
||||
"write-script-bash": `---
|
||||
name: write-script-bash
|
||||
description: MUST use when writing Bash scripts.
|
||||
|
||||
@@ -195,7 +195,8 @@
|
||||
'nu',
|
||||
'java',
|
||||
'ruby',
|
||||
'rlang'
|
||||
'rlang',
|
||||
'ansible'
|
||||
// for related places search: ADD_NEW_LANG
|
||||
].includes(lang ?? '')
|
||||
)
|
||||
@@ -216,7 +217,8 @@
|
||||
'nu',
|
||||
'java',
|
||||
'ruby',
|
||||
'rlang'
|
||||
'rlang',
|
||||
'ansible'
|
||||
// for related places search: ADD_NEW_LANG
|
||||
].includes(lang ?? '')
|
||||
)
|
||||
@@ -677,6 +679,10 @@ string ${windmillPathToCamelCaseName(path)} = await client.GetStringAsync(uri);
|
||||
editor.insertAtCursor(`get_variable("${path}")`)
|
||||
} else if (lang == 'rlang') {
|
||||
editor.insertAtCursor(`get_variable("${path}")`)
|
||||
} else if (lang == 'ansible') {
|
||||
// Ansible references Windmill variables by bare path in the YAML header
|
||||
// (e.g. `- variable: u/user/ssh_key` or `vault_password: u/user/...`)
|
||||
editor.insertAtCursor(path)
|
||||
}
|
||||
sendUserToast(`${name} inserted at cursor`)
|
||||
}}
|
||||
@@ -767,6 +773,10 @@ JsonNode ${windmillPathToCamelCaseName(path)} = JsonNode.Parse(await client.GetS
|
||||
} else {
|
||||
editor.insertAtCursor(`ATTACH 'res://${path}' AS db (TYPE ${t});`)
|
||||
}
|
||||
} else if (lang == 'ansible') {
|
||||
// Ansible references Windmill resources by bare path in the YAML header
|
||||
// (e.g. `- resource: u/user/...` under `inventory:` or `files:`)
|
||||
editor.insertAtCursor(path)
|
||||
}
|
||||
|
||||
sendUserToast(`${path} inserted at cursor`)
|
||||
|
||||
@@ -97,7 +97,8 @@ export const SUPPORTED_CHAT_SCRIPT_LANGUAGES = [
|
||||
'powershell',
|
||||
'csharp',
|
||||
'java',
|
||||
'duckdb'
|
||||
'duckdb',
|
||||
'ansible'
|
||||
]
|
||||
|
||||
export function getLangContext(
|
||||
@@ -308,7 +309,11 @@ INSTRUCTIONS:
|
||||
export function prepareScriptSystemMessage(
|
||||
currentModel: AIProviderModel,
|
||||
language: ScriptLang | 'bunnative',
|
||||
options: { isPreprocessor?: boolean; allowResourcesFetch?: boolean; workflowAsCode?: boolean } = {},
|
||||
options: {
|
||||
isPreprocessor?: boolean
|
||||
allowResourcesFetch?: boolean
|
||||
workflowAsCode?: boolean
|
||||
} = {},
|
||||
customPrompt?: string
|
||||
): ChatCompletionSystemMessageParam {
|
||||
let content = buildChatSystemPrompt(currentModel)
|
||||
|
||||
@@ -3328,6 +3328,102 @@ workspace related commands
|
||||
- Reorganize: \`wmill object-storage move <src> <dest>\` (same storage), \`wmill object-storage delete <file_key>\` (interactive confirm unless \`--yes\`).
|
||||
`;
|
||||
|
||||
export const LANG_ANSIBLE = `# Ansible
|
||||
|
||||
A Windmill Ansible script is a YAML document with two parts separated by a \`---\` line:
|
||||
|
||||
1. A **Windmill header** that declares the script's inputs, dependencies, inventory, file resources and options.
|
||||
2. One or more **Ansible plays** (the standard playbook content) executed with \`ansible-playbook\`.
|
||||
|
||||
## Structure
|
||||
|
||||
\`\`\`yaml
|
||||
---
|
||||
inventory:
|
||||
- resource_type: ansible_inventory
|
||||
# Pin an inventory by hardcoding the resource path (optional):
|
||||
# resource: u/user/your_inventory
|
||||
|
||||
options:
|
||||
- verbosity: vvv
|
||||
|
||||
# File resources/variables are written to their relative \`target\` location
|
||||
# before the playbook runs:
|
||||
# files:
|
||||
# - resource: u/user/fabulous_jinja_template
|
||||
# target: ./config_template.j2
|
||||
# - variable: u/user/ssh_key
|
||||
# target: ./ssh_key
|
||||
# mode: '0600'
|
||||
|
||||
# Inputs of the Windmill script. Each key becomes an Ansible variable usable
|
||||
# with {{ var_name }}. The JSON Schema is inferred from these declarations.
|
||||
extra_vars:
|
||||
world_qualifier:
|
||||
type: string
|
||||
|
||||
# If using Ansible Vault:
|
||||
# vault_password: u/user/ansible_vault_password
|
||||
|
||||
dependencies:
|
||||
galaxy:
|
||||
collections:
|
||||
- name: community.general
|
||||
roles:
|
||||
python:
|
||||
- jmespath
|
||||
---
|
||||
- name: Echo
|
||||
hosts: 127.0.0.1
|
||||
connection: local
|
||||
tasks:
|
||||
- name: Print debug message
|
||||
debug:
|
||||
msg: "Hello, {{ world_qualifier }} world!"
|
||||
\`\`\`
|
||||
|
||||
## Inputs (\`extra_vars\`)
|
||||
|
||||
- Each entry under \`extra_vars\` declares a Windmill script argument and is passed to the playbook as an Ansible variable (\`--extra-vars\`).
|
||||
- Reference them in tasks with Jinja: \`{{ world_qualifier }}\`.
|
||||
- Supported \`type\` values: \`string\`, \`number\`, \`boolean\`, \`object\` (and nested schemas). This is what generates the script's input form.
|
||||
|
||||
## Inventory
|
||||
|
||||
- \`inventory:\` with \`resource_type: ansible_inventory\` lets the user select an inventory resource at runtime; add \`resource: u/user/...\` to pin one.
|
||||
- \`dynamic_inventory\` entries reference a \`name\` (e.g. \`hcloud.yml\`) for cloud/dynamic inventories.
|
||||
|
||||
## File resources and variables
|
||||
|
||||
Under \`files:\`, materialize Windmill resources or variables onto disk before the run:
|
||||
- \`resource: <path>\` or \`variable: <path>\` — the Windmill object to fetch.
|
||||
- \`target: ./relative/path\` — where to write it (relative paths only).
|
||||
- \`mode: '0600'\` — optional octal file permission (useful for SSH keys).
|
||||
|
||||
## Dependencies
|
||||
|
||||
- \`dependencies.galaxy.collections\` / \`dependencies.galaxy.roles\` — installed via \`ansible-galaxy\`.
|
||||
- \`dependencies.python\` — pip packages available to Ansible modules (e.g. \`jmespath\` for the \`json_query\` filter).
|
||||
|
||||
## Output
|
||||
|
||||
The script result is read from a \`result.json\` file in the job directory. Write it from a task, e.g.:
|
||||
|
||||
\`\`\`yaml
|
||||
- name: Write result
|
||||
delegate_to: localhost
|
||||
copy:
|
||||
content: "{{ my_result | to_json }}"
|
||||
dest: result.json
|
||||
\`\`\`
|
||||
|
||||
## Notes
|
||||
|
||||
- The header keys (\`inventory\`, \`extra_vars\`, \`files\`, \`options\`, \`vault_password\`, \`dependencies\`) are Windmill-specific — do not confuse them with Ansible's own keys.
|
||||
- Use \`hosts: 127.0.0.1\` with \`connection: local\` for local tasks; otherwise rely on the selected inventory.
|
||||
- Keep the \`---\` separator between the Windmill header and the plays.
|
||||
`;
|
||||
|
||||
export const LANG_BASH = `# Bash
|
||||
|
||||
## Structure
|
||||
|
||||
@@ -27,6 +27,102 @@ e.g., `{ b: 1, a: 2 }` calls the flow with `a = 2` and `b = 1`, assuming the flo
|
||||
The preprocessor receives a single parameter called `event`.
|
||||
|
||||
|
||||
# Ansible
|
||||
|
||||
A Windmill Ansible script is a YAML document with two parts separated by a `---` line:
|
||||
|
||||
1. A **Windmill header** that declares the script's inputs, dependencies, inventory, file resources and options.
|
||||
2. One or more **Ansible plays** (the standard playbook content) executed with `ansible-playbook`.
|
||||
|
||||
## Structure
|
||||
|
||||
```yaml
|
||||
---
|
||||
inventory:
|
||||
- resource_type: ansible_inventory
|
||||
# Pin an inventory by hardcoding the resource path (optional):
|
||||
# resource: u/user/your_inventory
|
||||
|
||||
options:
|
||||
- verbosity: vvv
|
||||
|
||||
# File resources/variables are written to their relative `target` location
|
||||
# before the playbook runs:
|
||||
# files:
|
||||
# - resource: u/user/fabulous_jinja_template
|
||||
# target: ./config_template.j2
|
||||
# - variable: u/user/ssh_key
|
||||
# target: ./ssh_key
|
||||
# mode: '0600'
|
||||
|
||||
# Inputs of the Windmill script. Each key becomes an Ansible variable usable
|
||||
# with {{ var_name }}. The JSON Schema is inferred from these declarations.
|
||||
extra_vars:
|
||||
world_qualifier:
|
||||
type: string
|
||||
|
||||
# If using Ansible Vault:
|
||||
# vault_password: u/user/ansible_vault_password
|
||||
|
||||
dependencies:
|
||||
galaxy:
|
||||
collections:
|
||||
- name: community.general
|
||||
roles:
|
||||
python:
|
||||
- jmespath
|
||||
---
|
||||
- name: Echo
|
||||
hosts: 127.0.0.1
|
||||
connection: local
|
||||
tasks:
|
||||
- name: Print debug message
|
||||
debug:
|
||||
msg: "Hello, {{ world_qualifier }} world!"
|
||||
```
|
||||
|
||||
## Inputs (`extra_vars`)
|
||||
|
||||
- Each entry under `extra_vars` declares a Windmill script argument and is passed to the playbook as an Ansible variable (`--extra-vars`).
|
||||
- Reference them in tasks with Jinja: `{{ world_qualifier }}`.
|
||||
- Supported `type` values: `string`, `number`, `boolean`, `object` (and nested schemas). This is what generates the script's input form.
|
||||
|
||||
## Inventory
|
||||
|
||||
- `inventory:` with `resource_type: ansible_inventory` lets the user select an inventory resource at runtime; add `resource: u/user/...` to pin one.
|
||||
- `dynamic_inventory` entries reference a `name` (e.g. `hcloud.yml`) for cloud/dynamic inventories.
|
||||
|
||||
## File resources and variables
|
||||
|
||||
Under `files:`, materialize Windmill resources or variables onto disk before the run:
|
||||
- `resource: <path>` or `variable: <path>` — the Windmill object to fetch.
|
||||
- `target: ./relative/path` — where to write it (relative paths only).
|
||||
- `mode: '0600'` — optional octal file permission (useful for SSH keys).
|
||||
|
||||
## Dependencies
|
||||
|
||||
- `dependencies.galaxy.collections` / `dependencies.galaxy.roles` — installed via `ansible-galaxy`.
|
||||
- `dependencies.python` — pip packages available to Ansible modules (e.g. `jmespath` for the `json_query` filter).
|
||||
|
||||
## Output
|
||||
|
||||
The script result is read from a `result.json` file in the job directory. Write it from a task, e.g.:
|
||||
|
||||
```yaml
|
||||
- name: Write result
|
||||
delegate_to: localhost
|
||||
copy:
|
||||
content: "{{ my_result | to_json }}"
|
||||
dest: result.json
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The header keys (`inventory`, `extra_vars`, `files`, `options`, `vault_password`, `dependencies`) are Windmill-specific — do not confuse them with Ansible's own keys.
|
||||
- Use `hosts: 127.0.0.1` with `connection: local` for local tasks; otherwise rely on the selected inventory.
|
||||
- Keep the `---` separator between the Windmill header and the plays.
|
||||
|
||||
|
||||
# Bash
|
||||
|
||||
## Structure
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
---
|
||||
name: write-script-ansible
|
||||
description: MUST use when writing Ansible playbooks.
|
||||
---
|
||||
|
||||
## CLI Commands
|
||||
|
||||
Place scripts in a folder.
|
||||
|
||||
After writing, tell the user which command fits what they want to do:
|
||||
|
||||
- `wmill script preview <script_path>` — **default when iterating on a local script.** Runs the local file without deploying.
|
||||
- `wmill script run <path>` — runs the script **already deployed** in the workspace. Use only when the user explicitly wants to test the deployed version, not local edits.
|
||||
- `wmill generate-metadata` — regenerate the local `.script.yaml` (input schema) and `.lock` (resolved dependencies) for scripts you changed, and refresh their content hashes in `wmill-lock.yaml`. Local files only — **not** a deploy. See "Keep metadata in sync" below.
|
||||
- `wmill sync push` — deploy local changes to the workspace. Only suggest/run this when the user explicitly asks to deploy/publish/push — not when they say "run", "try", or "test".
|
||||
|
||||
### Preview vs run — choose by intent, not habit
|
||||
|
||||
If the user says "run the script", "try it", "test it", "does it work" while there are **local edits to the script file**, use `script preview`. Do NOT push the script to then `script run` it — pushing is a deploy, and deploying just to test overwrites the workspace version with untested changes.
|
||||
|
||||
Only use `script run` when:
|
||||
- The user explicitly says "run the deployed version" / "run what's on the server".
|
||||
- There is no local script being edited (you're just invoking an existing script).
|
||||
|
||||
Only use `sync push` when:
|
||||
- The user explicitly asks to deploy, publish, push, or ship.
|
||||
- The preview has already validated the change and the user wants it in the workspace.
|
||||
|
||||
### Keep metadata in sync after editing
|
||||
|
||||
`wmill-lock.yaml` tracks a content hash for each item. Editing a script's content — most importantly **adding or removing an import** or **changing `main`'s arguments** — invalidates that hash and leaves the `.lock`, the `.script.yaml` input schema, and the hash row out of date. Run `wmill generate-metadata` (scoped to what you touched) after such edits so the resolved lock, the auto-generated args UI (driven by `.script.yaml`), and `wmill-lock.yaml` all match the code. Leaving them stale produces spurious diffs in git-sync and CI.
|
||||
|
||||
This only writes local files (it is **not** a deploy), but it re-resolves dependencies, so it can bump unpinned versions (the same as deploying from the UI; expected, not a bug). So by default offer it and run it once the user agrees, rather than running it silently after every edit — unless the project's `AGENTS.md` opts into running metadata automatically (see the "Keeping metadata in sync" preference there). Either way YOU run the command, not the user. After running it, diff the regenerated `.lock` / `.script.lock` files and tell the user which dependency versions changed (e.g. `requests 2.31.0 → 2.32.0`), so they can catch an unwanted bump before deploying — even under `Metadata: auto`, since it's information, not a confirmation gate. Pin versions in code to keep them fixed.
|
||||
|
||||
With no path argument, `generate-metadata` regenerates only the items whose content hash drifted — not everything. Imports propagate: editing a script that others import marks every importer stale too, so a one-line change to a shared module can regenerate many locks (by design — their locks must reflect the imported code). If it touches more than you expect, run `wmill generate-metadata --dry-run` — it lists each stale item with a reason (`content changed` or `depends on <path>`) without changing anything — then narrow with a path argument (`wmill generate-metadata f/foo`) or `--strict-folder-boundaries`.
|
||||
|
||||
If the on-disk `.lock` and `.script.yaml` are already correct and only `wmill-lock.yaml` needs its hashes refreshed (hash drift, or bootstrapping missing entries), use `wmill generate-metadata rehash` — it re-records hashes from disk with no backend round-trip and no dependency changes.
|
||||
|
||||
### After writing — offer to test, don't wait passively
|
||||
|
||||
If the user hasn't already told you to run/test/preview the script, offer it as a one-sentence next step (e.g. "Want me to run `wmill script preview` with sample args?"). Do not present a multi-option menu.
|
||||
|
||||
If the user already asked to test/run/try the script in their original request, skip the offer and just execute `wmill script preview <path> -d '<args>'` directly — pick plausible args from the script's declared parameters. The shape varies by language: `main(...)` for code languages, the SQL dialect's own placeholder syntax (`$1` for PostgreSQL, `?` for MySQL/Snowflake, `@P1` for MSSQL, `@name` for BigQuery, etc.), positional `$1`, `$2`, … for Bash, `param(...)` for PowerShell.
|
||||
|
||||
`wmill script preview` does not deploy, but it still executes script code and may cause side effects; run it yourself when the user asked to test/preview (or after confirming that execution is intended). `wmill generate-metadata` does not deploy either — it only writes local files (locks, schemas, hashes) — but offer it before running (or run automatically if the project's `AGENTS.md` opts in), per "Keep metadata in sync" above. Only `wmill sync push` deploys to the workspace — run it only when the user explicitly asks to deploy/publish/push.
|
||||
|
||||
For a **visual** open-the-script-in-the-dev-page preview (rather than `script preview`'s run-and-print-result), use the `preview` skill.
|
||||
|
||||
Use `wmill resource-type list --schema` to discover available resource types.
|
||||
|
||||
# Ansible
|
||||
|
||||
A Windmill Ansible script is a YAML document with two parts separated by a `---` line:
|
||||
|
||||
1. A **Windmill header** that declares the script's inputs, dependencies, inventory, file resources and options.
|
||||
2. One or more **Ansible plays** (the standard playbook content) executed with `ansible-playbook`.
|
||||
|
||||
## Structure
|
||||
|
||||
```yaml
|
||||
---
|
||||
inventory:
|
||||
- resource_type: ansible_inventory
|
||||
# Pin an inventory by hardcoding the resource path (optional):
|
||||
# resource: u/user/your_inventory
|
||||
|
||||
options:
|
||||
- verbosity: vvv
|
||||
|
||||
# File resources/variables are written to their relative `target` location
|
||||
# before the playbook runs:
|
||||
# files:
|
||||
# - resource: u/user/fabulous_jinja_template
|
||||
# target: ./config_template.j2
|
||||
# - variable: u/user/ssh_key
|
||||
# target: ./ssh_key
|
||||
# mode: '0600'
|
||||
|
||||
# Inputs of the Windmill script. Each key becomes an Ansible variable usable
|
||||
# with {{ var_name }}. The JSON Schema is inferred from these declarations.
|
||||
extra_vars:
|
||||
world_qualifier:
|
||||
type: string
|
||||
|
||||
# If using Ansible Vault:
|
||||
# vault_password: u/user/ansible_vault_password
|
||||
|
||||
dependencies:
|
||||
galaxy:
|
||||
collections:
|
||||
- name: community.general
|
||||
roles:
|
||||
python:
|
||||
- jmespath
|
||||
---
|
||||
- name: Echo
|
||||
hosts: 127.0.0.1
|
||||
connection: local
|
||||
tasks:
|
||||
- name: Print debug message
|
||||
debug:
|
||||
msg: "Hello, {{ world_qualifier }} world!"
|
||||
```
|
||||
|
||||
## Inputs (`extra_vars`)
|
||||
|
||||
- Each entry under `extra_vars` declares a Windmill script argument and is passed to the playbook as an Ansible variable (`--extra-vars`).
|
||||
- Reference them in tasks with Jinja: `{{ world_qualifier }}`.
|
||||
- Supported `type` values: `string`, `number`, `boolean`, `object` (and nested schemas). This is what generates the script's input form.
|
||||
|
||||
## Inventory
|
||||
|
||||
- `inventory:` with `resource_type: ansible_inventory` lets the user select an inventory resource at runtime; add `resource: u/user/...` to pin one.
|
||||
- `dynamic_inventory` entries reference a `name` (e.g. `hcloud.yml`) for cloud/dynamic inventories.
|
||||
|
||||
## File resources and variables
|
||||
|
||||
Under `files:`, materialize Windmill resources or variables onto disk before the run:
|
||||
- `resource: <path>` or `variable: <path>` — the Windmill object to fetch.
|
||||
- `target: ./relative/path` — where to write it (relative paths only).
|
||||
- `mode: '0600'` — optional octal file permission (useful for SSH keys).
|
||||
|
||||
## Dependencies
|
||||
|
||||
- `dependencies.galaxy.collections` / `dependencies.galaxy.roles` — installed via `ansible-galaxy`.
|
||||
- `dependencies.python` — pip packages available to Ansible modules (e.g. `jmespath` for the `json_query` filter).
|
||||
|
||||
## Output
|
||||
|
||||
The script result is read from a `result.json` file in the job directory. Write it from a task, e.g.:
|
||||
|
||||
```yaml
|
||||
- name: Write result
|
||||
delegate_to: localhost
|
||||
copy:
|
||||
content: "{{ my_result | to_json }}"
|
||||
dest: result.json
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The header keys (`inventory`, `extra_vars`, `files`, `options`, `vault_password`, `dependencies`) are Windmill-specific — do not confuse them with Ansible's own keys.
|
||||
- Use `hosts: 127.0.0.1` with `connection: local` for local tasks; otherwise rely on the selected inventory.
|
||||
- Keep the `---` separator between the Windmill header and the plays.
|
||||
@@ -0,0 +1,94 @@
|
||||
# Ansible
|
||||
|
||||
A Windmill Ansible script is a YAML document with two parts separated by a `---` line:
|
||||
|
||||
1. A **Windmill header** that declares the script's inputs, dependencies, inventory, file resources and options.
|
||||
2. One or more **Ansible plays** (the standard playbook content) executed with `ansible-playbook`.
|
||||
|
||||
## Structure
|
||||
|
||||
```yaml
|
||||
---
|
||||
inventory:
|
||||
- resource_type: ansible_inventory
|
||||
# Pin an inventory by hardcoding the resource path (optional):
|
||||
# resource: u/user/your_inventory
|
||||
|
||||
options:
|
||||
- verbosity: vvv
|
||||
|
||||
# File resources/variables are written to their relative `target` location
|
||||
# before the playbook runs:
|
||||
# files:
|
||||
# - resource: u/user/fabulous_jinja_template
|
||||
# target: ./config_template.j2
|
||||
# - variable: u/user/ssh_key
|
||||
# target: ./ssh_key
|
||||
# mode: '0600'
|
||||
|
||||
# Inputs of the Windmill script. Each key becomes an Ansible variable usable
|
||||
# with {{ var_name }}. The JSON Schema is inferred from these declarations.
|
||||
extra_vars:
|
||||
world_qualifier:
|
||||
type: string
|
||||
|
||||
# If using Ansible Vault:
|
||||
# vault_password: u/user/ansible_vault_password
|
||||
|
||||
dependencies:
|
||||
galaxy:
|
||||
collections:
|
||||
- name: community.general
|
||||
roles:
|
||||
python:
|
||||
- jmespath
|
||||
---
|
||||
- name: Echo
|
||||
hosts: 127.0.0.1
|
||||
connection: local
|
||||
tasks:
|
||||
- name: Print debug message
|
||||
debug:
|
||||
msg: "Hello, {{ world_qualifier }} world!"
|
||||
```
|
||||
|
||||
## Inputs (`extra_vars`)
|
||||
|
||||
- Each entry under `extra_vars` declares a Windmill script argument and is passed to the playbook as an Ansible variable (`--extra-vars`).
|
||||
- Reference them in tasks with Jinja: `{{ world_qualifier }}`.
|
||||
- Supported `type` values: `string`, `number`, `boolean`, `object` (and nested schemas). This is what generates the script's input form.
|
||||
|
||||
## Inventory
|
||||
|
||||
- `inventory:` with `resource_type: ansible_inventory` lets the user select an inventory resource at runtime; add `resource: u/user/...` to pin one.
|
||||
- `dynamic_inventory` entries reference a `name` (e.g. `hcloud.yml`) for cloud/dynamic inventories.
|
||||
|
||||
## File resources and variables
|
||||
|
||||
Under `files:`, materialize Windmill resources or variables onto disk before the run:
|
||||
- `resource: <path>` or `variable: <path>` — the Windmill object to fetch.
|
||||
- `target: ./relative/path` — where to write it (relative paths only).
|
||||
- `mode: '0600'` — optional octal file permission (useful for SSH keys).
|
||||
|
||||
## Dependencies
|
||||
|
||||
- `dependencies.galaxy.collections` / `dependencies.galaxy.roles` — installed via `ansible-galaxy`.
|
||||
- `dependencies.python` — pip packages available to Ansible modules (e.g. `jmespath` for the `json_query` filter).
|
||||
|
||||
## Output
|
||||
|
||||
The script result is read from a `result.json` file in the job directory. Write it from a task, e.g.:
|
||||
|
||||
```yaml
|
||||
- name: Write result
|
||||
delegate_to: localhost
|
||||
copy:
|
||||
content: "{{ my_result | to_json }}"
|
||||
dest: result.json
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The header keys (`inventory`, `extra_vars`, `files`, `options`, `vault_password`, `dependencies`) are Windmill-specific — do not confuse them with Ansible's own keys.
|
||||
- Use `hosts: 127.0.0.1` with `connection: local` for local tasks; otherwise rely on the selected inventory.
|
||||
- Keep the `---` separator between the Windmill header and the plays.
|
||||
@@ -184,6 +184,11 @@ LANGUAGE_METADATA = {
|
||||
'description': 'MUST use when writing R scripts.',
|
||||
'use_cases': 'R statistical computing, data analysis, visualization'
|
||||
},
|
||||
'ansible': {
|
||||
'name': 'Ansible',
|
||||
'description': 'MUST use when writing Ansible playbooks.',
|
||||
'use_cases': 'infrastructure automation, configuration management, provisioning'
|
||||
},
|
||||
}
|
||||
|
||||
# Languages that use TypeScript SDK. 'nativets' is kept here (despite having no
|
||||
|
||||
Reference in New Issue
Block a user