ci: add freshness check for auto-generated system prompts (#8338)

* ci: add freshness check for auto-generated system prompts

Add a CI workflow and script to verify system_prompts/auto-generated/
stays in sync with its source files (SDKs, schemas, CLI commands, etc).
Also remove the hardcoded CLI version from generated output to avoid
unnecessary churn on every release.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* imports

* imports

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* regenerate system prompts after rebase on main

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Ruben Fiszel
2026-03-12 14:44:27 +00:00
committed by GitHub
parent 9f7f666af4
commit 749964e326
18 changed files with 2827 additions and 2606 deletions

View File

@@ -0,0 +1,37 @@
name: Check system prompts freshness
on:
push:
paths:
- "system_prompts/**"
- "typescript-client/**"
- "python-client/wmill/wmill/client.py"
- "openflow.openapi.yaml"
- "backend/windmill-api/openapi.yaml"
- "cli/src/main.ts"
- "cli/src/commands/**"
pull_request:
paths:
- "system_prompts/**"
- "typescript-client/**"
- "python-client/wmill/wmill/client.py"
- "openflow.openapi.yaml"
- "backend/windmill-api/openapi.yaml"
- "cli/src/main.ts"
- "cli/src/commands/**"
jobs:
check-freshness:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: pip install pyyaml
- name: Check auto-generated files are up-to-date
run: bash system_prompts/check-freshness.sh

1
.gitignore vendored
View File

@@ -27,3 +27,4 @@ typescript-client/node_modules
frontend/.svelte-kit
backend/chrome_profiler.json
.fast-check/
__pycache__/

File diff suppressed because it is too large Load Diff

View File

@@ -2,8 +2,6 @@
The Windmill CLI (`wmill`) provides commands for managing scripts, flows, apps, and other resources.
Current version: 1.653.0
## Global Options
- `--workspace <workspace:string>` - Specify the target workspace. This overrides the default workspace.

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -32,6 +32,11 @@ properties:
- earliest
description: Initial offset behavior when consumer group has no committed offset.
'latest' starts from new messages only, 'earliest' starts from the beginning.
auto_commit:
type: boolean
description: When true (default), offsets are committed automatically after receiving
each message. When false, you must manually commit offsets using the commit_offsets
endpoint.
error_handler_path:
type: string
description: Path to a script or flow to run when the triggered job fails

View File

@@ -1126,36 +1126,6 @@ SELECT * FROM users WHERE name = ? AND age > ?;
Import: import * as wmill from 'windmill-client'
/**
* Create a SQL template function for PostgreSQL/datatable queries
* @param name - Database/datatable name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.datatable()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}::int
* `.fetch()
*/
datatable(name: string = "main"): DatatableSqlTemplateFunction
/**
* Create a SQL template function for DuckDB/ducklake queries
* @param name - DuckDB database name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.ducklake()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}
* `.fetch()
*/
ducklake(name: string = "main"): SqlTemplateFunction
/**
* Initialize the Windmill client with authentication token and base URL
* @param token - Authentication token (defaults to WM_TOKEN env variable)
@@ -1649,6 +1619,45 @@ waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ v
*/
async parallel<T, R>(items: T[], fn: (item: T) => PromiseLike<R> | R, options?: { concurrency?: number },): Promise<R[]>
/**
* Commit Kafka offsets for a trigger with auto_commit disabled.
* @param triggerPath - Path to the Kafka trigger (from event.wm_trigger.trigger_path)
* @param topic - Kafka topic name (from event.topic)
* @param partition - Partition number (from event.partition)
* @param offset - Message offset to commit (from event.offset)
*/
async commitKafkaOffsets(triggerPath: string, topic: string, partition: number, offset: number,): Promise<void>
/**
* Create a SQL template function for PostgreSQL/datatable queries
* @param name - Database/datatable name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.datatable()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}::int
* `.fetch()
*/
datatable(name: string = "main"): DatatableSqlTemplateFunction
/**
* Create a SQL template function for DuckDB/ducklake queries
* @param name - DuckDB database name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.ducklake()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}
* `.fetch()
*/
ducklake(name: string = "main"): SqlTemplateFunction
# Python SDK (wmill)
@@ -2321,3 +2330,12 @@ async def wait_for_approval(timeout: int = 1800, form: dict | None = None) -> di
# results = await parallel(items, process, concurrency=5)
async def parallel(items, fn, concurrency: Optional[int] = None)
# Commit Kafka offsets for a trigger with auto_commit disabled.
#
# Args:
# trigger_path: Path to the Kafka trigger (from event['wm_trigger']['trigger_path'])
# topic: Kafka topic name (from event['topic'])
# partition: Partition number (from event['partition'])
# offset: Message offset to commit (from event['offset'])
def commit_kafka_offsets(trigger_path: str, topic: str, partition: int, offset: int) -> None

View File

@@ -669,3 +669,12 @@ async def wait_for_approval(timeout: int = 1800, form: dict | None = None) -> di
# results = await parallel(items, process, concurrency=5)
async def parallel(items, fn, concurrency: Optional[int] = None)
# Commit Kafka offsets for a trigger with auto_commit disabled.
#
# Args:
# trigger_path: Path to the Kafka trigger (from event['wm_trigger']['trigger_path'])
# topic: Kafka topic name (from event['topic'])
# partition: Partition number (from event['partition'])
# offset: Message offset to commit (from event['offset'])
def commit_kafka_offsets(trigger_path: str, topic: str, partition: int, offset: int) -> None

View File

@@ -2,36 +2,6 @@
Import: import * as wmill from 'windmill-client'
/**
* Create a SQL template function for PostgreSQL/datatable queries
* @param name - Database/datatable name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.datatable()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}::int
* `.fetch()
*/
datatable(name: string = "main"): DatatableSqlTemplateFunction
/**
* Create a SQL template function for DuckDB/ducklake queries
* @param name - DuckDB database name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.ducklake()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}
* `.fetch()
*/
ducklake(name: string = "main"): SqlTemplateFunction
/**
* Initialize the Windmill client with authentication token and base URL
* @param token - Authentication token (defaults to WM_TOKEN env variable)
@@ -524,3 +494,42 @@ waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ v
* const results = await parallel(items, process, { concurrency: 5 });
*/
async parallel<T, R>(items: T[], fn: (item: T) => PromiseLike<R> | R, options?: { concurrency?: number },): Promise<R[]>
/**
* Commit Kafka offsets for a trigger with auto_commit disabled.
* @param triggerPath - Path to the Kafka trigger (from event.wm_trigger.trigger_path)
* @param topic - Kafka topic name (from event.topic)
* @param partition - Partition number (from event.partition)
* @param offset - Message offset to commit (from event.offset)
*/
async commitKafkaOffsets(triggerPath: string, topic: string, partition: number, offset: number,): Promise<void>
/**
* Create a SQL template function for PostgreSQL/datatable queries
* @param name - Database/datatable name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.datatable()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}::int
* `.fetch()
*/
datatable(name: string = "main"): DatatableSqlTemplateFunction
/**
* Create a SQL template function for DuckDB/ducklake queries
* @param name - DuckDB database name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.ducklake()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}
* `.fetch()
*/
ducklake(name: string = "main"): SqlTemplateFunction

View File

@@ -7,8 +7,6 @@ description: MUST use when using the CLI.
The Windmill CLI (`wmill`) provides commands for managing scripts, flows, apps, and other resources.
Current version: 1.653.0
## Global Options
- `--workspace <workspace:string>` - Specify the target workspace. This overrides the default workspace.

View File

@@ -131,36 +131,6 @@ const result: S3Object = await wmill.writeS3File(
Import: import * as wmill from 'windmill-client'
/**
* Create a SQL template function for PostgreSQL/datatable queries
* @param name - Database/datatable name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.datatable()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}::int
* `.fetch()
*/
datatable(name: string = "main"): DatatableSqlTemplateFunction
/**
* Create a SQL template function for DuckDB/ducklake queries
* @param name - DuckDB database name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.ducklake()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}
* `.fetch()
*/
ducklake(name: string = "main"): SqlTemplateFunction
/**
* Initialize the Windmill client with authentication token and base URL
* @param token - Authentication token (defaults to WM_TOKEN env variable)
@@ -653,3 +623,42 @@ waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ v
* const results = await parallel(items, process, { concurrency: 5 });
*/
async parallel<T, R>(items: T[], fn: (item: T) => PromiseLike<R> | R, options?: { concurrency?: number },): Promise<R[]>
/**
* Commit Kafka offsets for a trigger with auto_commit disabled.
* @param triggerPath - Path to the Kafka trigger (from event.wm_trigger.trigger_path)
* @param topic - Kafka topic name (from event.topic)
* @param partition - Partition number (from event.partition)
* @param offset - Message offset to commit (from event.offset)
*/
async commitKafkaOffsets(triggerPath: string, topic: string, partition: number, offset: number,): Promise<void>
/**
* Create a SQL template function for PostgreSQL/datatable queries
* @param name - Database/datatable name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.datatable()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}::int
* `.fetch()
*/
datatable(name: string = "main"): DatatableSqlTemplateFunction
/**
* Create a SQL template function for DuckDB/ducklake queries
* @param name - DuckDB database name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.ducklake()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}
* `.fetch()
*/
ducklake(name: string = "main"): SqlTemplateFunction

View File

@@ -129,36 +129,6 @@ const result: S3Object = await wmill.writeS3File(
Import: import * as wmill from 'windmill-client'
/**
* Create a SQL template function for PostgreSQL/datatable queries
* @param name - Database/datatable name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.datatable()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}::int
* `.fetch()
*/
datatable(name: string = "main"): DatatableSqlTemplateFunction
/**
* Create a SQL template function for DuckDB/ducklake queries
* @param name - DuckDB database name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.ducklake()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}
* `.fetch()
*/
ducklake(name: string = "main"): SqlTemplateFunction
/**
* Initialize the Windmill client with authentication token and base URL
* @param token - Authentication token (defaults to WM_TOKEN env variable)
@@ -651,3 +621,42 @@ waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ v
* const results = await parallel(items, process, { concurrency: 5 });
*/
async parallel<T, R>(items: T[], fn: (item: T) => PromiseLike<R> | R, options?: { concurrency?: number },): Promise<R[]>
/**
* Commit Kafka offsets for a trigger with auto_commit disabled.
* @param triggerPath - Path to the Kafka trigger (from event.wm_trigger.trigger_path)
* @param topic - Kafka topic name (from event.topic)
* @param partition - Partition number (from event.partition)
* @param offset - Message offset to commit (from event.offset)
*/
async commitKafkaOffsets(triggerPath: string, topic: string, partition: number, offset: number,): Promise<void>
/**
* Create a SQL template function for PostgreSQL/datatable queries
* @param name - Database/datatable name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.datatable()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}::int
* `.fetch()
*/
datatable(name: string = "main"): DatatableSqlTemplateFunction
/**
* Create a SQL template function for DuckDB/ducklake queries
* @param name - DuckDB database name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.ducklake()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}
* `.fetch()
*/
ducklake(name: string = "main"): SqlTemplateFunction

View File

@@ -135,36 +135,6 @@ const result: S3Object = await wmill.writeS3File(
Import: import * as wmill from 'windmill-client'
/**
* Create a SQL template function for PostgreSQL/datatable queries
* @param name - Database/datatable name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.datatable()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}::int
* `.fetch()
*/
datatable(name: string = "main"): DatatableSqlTemplateFunction
/**
* Create a SQL template function for DuckDB/ducklake queries
* @param name - DuckDB database name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.ducklake()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}
* `.fetch()
*/
ducklake(name: string = "main"): SqlTemplateFunction
/**
* Initialize the Windmill client with authentication token and base URL
* @param token - Authentication token (defaults to WM_TOKEN env variable)
@@ -657,3 +627,42 @@ waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ v
* const results = await parallel(items, process, { concurrency: 5 });
*/
async parallel<T, R>(items: T[], fn: (item: T) => PromiseLike<R> | R, options?: { concurrency?: number },): Promise<R[]>
/**
* Commit Kafka offsets for a trigger with auto_commit disabled.
* @param triggerPath - Path to the Kafka trigger (from event.wm_trigger.trigger_path)
* @param topic - Kafka topic name (from event.topic)
* @param partition - Partition number (from event.partition)
* @param offset - Message offset to commit (from event.offset)
*/
async commitKafkaOffsets(triggerPath: string, topic: string, partition: number, offset: number,): Promise<void>
/**
* Create a SQL template function for PostgreSQL/datatable queries
* @param name - Database/datatable name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.datatable()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}::int
* `.fetch()
*/
datatable(name: string = "main"): DatatableSqlTemplateFunction
/**
* Create a SQL template function for DuckDB/ducklake queries
* @param name - DuckDB database name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.ducklake()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}
* `.fetch()
*/
ducklake(name: string = "main"): SqlTemplateFunction

View File

@@ -96,36 +96,6 @@ export async function preprocessor(event: Event) {
Import: import * as wmill from 'windmill-client'
/**
* Create a SQL template function for PostgreSQL/datatable queries
* @param name - Database/datatable name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.datatable()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}::int
* `.fetch()
*/
datatable(name: string = "main"): DatatableSqlTemplateFunction
/**
* Create a SQL template function for DuckDB/ducklake queries
* @param name - DuckDB database name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.ducklake()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}
* `.fetch()
*/
ducklake(name: string = "main"): SqlTemplateFunction
/**
* Initialize the Windmill client with authentication token and base URL
* @param token - Authentication token (defaults to WM_TOKEN env variable)
@@ -618,3 +588,42 @@ waitForApproval(options?: { timeout?: number; form?: object; }): PromiseLike<{ v
* const results = await parallel(items, process, { concurrency: 5 });
*/
async parallel<T, R>(items: T[], fn: (item: T) => PromiseLike<R> | R, options?: { concurrency?: number },): Promise<R[]>
/**
* Commit Kafka offsets for a trigger with auto_commit disabled.
* @param triggerPath - Path to the Kafka trigger (from event.wm_trigger.trigger_path)
* @param topic - Kafka topic name (from event.topic)
* @param partition - Partition number (from event.partition)
* @param offset - Message offset to commit (from event.offset)
*/
async commitKafkaOffsets(triggerPath: string, topic: string, partition: number, offset: number,): Promise<void>
/**
* Create a SQL template function for PostgreSQL/datatable queries
* @param name - Database/datatable name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.datatable()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}::int
* `.fetch()
*/
datatable(name: string = "main"): DatatableSqlTemplateFunction
/**
* Create a SQL template function for DuckDB/ducklake queries
* @param name - DuckDB database name (default: "main")
* @returns SQL template function for building parameterized queries
* @example
* let sql = wmill.ducklake()
* let name = 'Robin'
* let age = 21
* await sql`
* SELECT * FROM friends
* WHERE name = ${name} AND age = ${age}
* `.fetch()
*/
ducklake(name: string = "main"): SqlTemplateFunction

View File

@@ -804,3 +804,12 @@ async def wait_for_approval(timeout: int = 1800, form: dict | None = None) -> di
# results = await parallel(items, process, concurrency=5)
async def parallel(items, fn, concurrency: Optional[int] = None)
# Commit Kafka offsets for a trigger with auto_commit disabled.
#
# Args:
# trigger_path: Path to the Kafka trigger (from event['wm_trigger']['trigger_path'])
# topic: Kafka topic name (from event['topic'])
# partition: Partition number (from event['partition'])
# offset: Message offset to commit (from event['offset'])
def commit_kafka_offsets(trigger_path: str, topic: str, partition: int, offset: int) -> None

View File

@@ -0,0 +1,40 @@
#!/usr/bin/env bash
# Check that auto-generated system prompts are up-to-date with their sources.
# Usage: bash system_prompts/check-freshness.sh
# Exit code 0 = fresh, 1 = stale (with diff printed)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
ROOT_DIR="$SCRIPT_DIR/.."
GENERATED_DIR="$SCRIPT_DIR/auto-generated"
CLI_SKILLS="$ROOT_DIR/cli/src/guidance/skills.ts"
# Snapshot current state
BEFORE=$(git -C "$ROOT_DIR" diff -- "$GENERATED_DIR" "$CLI_SKILLS")
UNTRACKED_BEFORE=$(git -C "$ROOT_DIR" ls-files --others --exclude-standard -- "$GENERATED_DIR")
# Regenerate
echo "Running generate.py..."
python3 "$SCRIPT_DIR/generate.py"
# Compare
AFTER=$(git -C "$ROOT_DIR" diff -- "$GENERATED_DIR" "$CLI_SKILLS")
UNTRACKED_AFTER=$(git -C "$ROOT_DIR" ls-files --others --exclude-standard -- "$GENERATED_DIR")
if [ "$BEFORE" = "$AFTER" ] && [ "$UNTRACKED_BEFORE" = "$UNTRACKED_AFTER" ]; then
echo "Auto-generated system prompts are up-to-date."
exit 0
else
echo "ERROR: Auto-generated system prompts are stale!"
echo "Run 'python3 system_prompts/generate.py' and commit the result."
echo ""
echo "Diff:"
git -C "$ROOT_DIR" diff -- "$GENERATED_DIR" "$CLI_SKILLS"
if [ "$UNTRACKED_BEFORE" != "$UNTRACKED_AFTER" ]; then
echo ""
echo "New untracked files:"
git -C "$ROOT_DIR" ls-files --others --exclude-standard -- "$GENERATED_DIR"
fi
exit 1
fi

View File

@@ -499,9 +499,6 @@ def generate_cli_commands_markdown(cli_data: dict) -> str:
md = "# Windmill CLI Commands\n\n"
md += "The Windmill CLI (`wmill`) provides commands for managing scripts, flows, apps, and other resources.\n\n"
if cli_data.get('version'):
md += f"Current version: {cli_data['version']}\n\n"
# Global options
if cli_data.get('global_options'):
md += "## Global Options\n\n"
@@ -922,7 +919,7 @@ def main():
# Read SDK files
ts_content = ''
if TS_SDK_DIR.exists():
for ts_file in TS_SDK_DIR.glob('*.ts'):
for ts_file in sorted(TS_SDK_DIR.glob('*.ts')):
if not ts_file.name.endswith('.d.ts'):
ts_content += ts_file.read_text() + '\n'
py_content = PY_SDK_PATH.read_text() if PY_SDK_PATH.exists() else ''
@@ -960,7 +957,7 @@ def main():
# Read language files
languages = {}
for lang_file in languages_dir.glob("*.md"):
for lang_file in sorted(languages_dir.glob("*.md")):
languages[lang_file.stem] = lang_file.read_text()
# Extract and generate CLI commands documentation