* fix: auto-create missing folders during sync push for non-admin users Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: show missing folders in sync push summary before confirmation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: improve sync push folder auto-creation error handling and json output Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: only treat 404 as missing folder in getFolder check Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: remove obsolete Deno compatibility layer from yaml-validator Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore(cli): add @types/bun dev dependency Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(cli): replace auto-create folders with `wmill folder add-missing` command Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(cli): improve folder commands with summary field and simpler push API Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(cli): add confirmation prompt to folder add-missing command Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor(cli): simplify missing folder check to use local stat instead of remote API Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * update skills * feat(cli): warn admins but block non-admins on missing folder.meta.yaml Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * cleaning * cleaning * test(cli): add tests for missing folder detection and folder commands - Add tests for `folder new`, `folder push`, `folder add-missing` commands - Add tests for sync push missing folder.meta.yaml detection (admin warning, non-admin block) - Fix getBasePostgresUrl to strip query params (e.g. ?sslmode=disable) from DATABASE_URL - Add createNonAdminUser and runCLIWithToken test utilities to test_backend.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(cli): unify runCLICommand with optional token parameter Replace separate runCLIWithToken utility with an optional { workspace?, token? } options object on the existing runCLICommand across all backends. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * own workspace * test(cli): isolate folder_missing_meta tests with per-test workspace * test(cli): shorten isolated workspace id/name for workspace limits * test(cli): archive temp isolated workspaces after each folder test --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Windmill YAML Validator
A TypeScript-based YAML validator for Windmill flow, schedule, and trigger files.
Overview
The windmill-yaml-validator provides runtime validation for Windmill YAML files. It is used by editor integrations to show validation errors while editing:
flow.yaml/flow.yml*.schedule.yaml/*.schedule.yml*.{http|websocket|kafka|nats|postgres|mqtt|sqs|gcp}_trigger.yaml(or.yml)
Features
- Unified validation API: One validator class for flow/schedule/trigger files
- Schema-based validation: Uses OpenFlow and backend OpenAPI-derived schemas
- Detailed error reporting: Returns comprehensive error information with specific paths to invalid fields
Installation
npm install windmill-yaml-validator
Usage
Basic Validation
import { WindmillYamlValidator } from "windmill-yaml-validator";
const validator = new WindmillYamlValidator();
const flowYaml = `
summary: Test Flow
value:
modules: []
`;
const flowResult = validator.validate(flowYaml, { type: "flow" });
const scheduleYaml = `
schedule: "0 0 12 * * *"
timezone: "UTC"
enabled: true
script_path: "f/jobs/daily_sync"
is_flow: false
`;
const scheduleResult = validator.validate(scheduleYaml, { type: "schedule" });
const triggerYaml = `
script_path: "f/triggers/http_handler"
is_flow: false
route_path: "api/webhook"
request_type: "sync"
authentication_method: "none"
http_method: "post"
is_static_website: false
workspaced_route: false
wrap_body: false
raw_string: false
`;
const triggerResult = validator.validate(triggerYaml, {
type: "trigger",
triggerKind: "http",
});
console.log(flowResult.errors, scheduleResult.errors, triggerResult.errors);
Target Inference by Filename
import {
WindmillYamlValidator,
getValidationTargetFromFilename,
} from "windmill-yaml-validator";
const validator = new WindmillYamlValidator();
const target = getValidationTargetFromFilename(
"f/webhooks/order_created.http_trigger.yaml"
);
if (target) {
const result = validator.validate(fileContents, target);
console.log(result.errors);
}
Error Handling
const invalidYaml = `
summary: 123 # Should be a string
value:
modules:
- id: step1
value:
type: rawscript
language: invalid_language # Invalid enum value
`;
const result = validator.validate(invalidYaml, { type: "flow" });
result.errors.forEach((error) => {
console.log(`Error at ${error.instancePath}: ${error.message}`);
// Example output:
// Error at /summary: must be string
// Error at /value/modules/0/value/language: must be equal to one of the allowed values
});
API
WindmillYamlValidator
Main validator class for Windmill YAML validation.
Constructor
new WindmillYamlValidator();
Initializes AJV validators for flow, schedule, and trigger schemas.
Methods
validate(doc: string, target: ValidationTarget)
Validates a YAML document against the selected target schema.
Parameters:
doc(string): YAML document stringtarget(ValidationTarget):{ type: "flow" }{ type: "schedule" }{ type: "trigger", triggerKind: "http" | "websocket" | "kafka" | "nats" | "postgres" | "mqtt" | "sqs" | "gcp" | "email" }
Returns:
{
parsed: YamlParserResult<unknown>; // Parsed YAML with source pointers
errors: ErrorObject[]; // Array of validation errors (empty if valid)
}
Throws:
- Error if
docis not a string
getValidationTargetFromFilename(path: string)
Infers validation target from file naming conventions. Returns null for unsupported files.
Development
Building
npm run build
The build process:
- Runs
gen_openflow_schema.shto generate:src/gen/openflow.jsonsrc/gen/schedule.jsonsrc/gen/triggers/*.json
- Removes discriminator mappings (not supported by AJV)
- Compiles TypeScript to JavaScript
Testing
npm test
Run tests in watch mode:
npm test:watch
Testing locally with the CLI
To test local changes before publishing, use npm link:
# In windmill-yaml-validator/
npm run build
npm link
# In cli/
npm link windmill-yaml-validator
bun run src/main.ts lint
Schema Generation
The validator uses a JSON schema generated from the OpenAPI specification:
./gen_openflow_schema.sh
This script:
- Converts
openflow.openapi.yamlandbackend/windmill-api/openapi.yamlinto JSON - Removes discriminator mappings for AJV compatibility
- Removes the
ToolValuediscriminator entirely (see below) - Generates standalone schedule/trigger schemas for CLI file shape
Why Remove Discriminators?
The OpenFlow schema uses OpenAPI discriminators for efficient type resolution in oneOf schemas. However, AJV's discriminator support has limitations:
- Discriminator Mappings: Not fully supported by AJV, so they are removed from all schemas
- ToolValue Discriminator: Completely removed because
FlowModuleToolusesallOfcomposition, which prevents AJV from finding the discriminator property (tool_type) at the expected location
Impact: Without discriminators, AJV falls back to standard oneOf validation, which:
- Tests each alternative until one matches
- Is slightly slower but still performant for our use case
- Provides the same validation correctness
- Works correctly with complex schema compositions like
allOf
Breaking Change
FlowValidator and validateFlow() were replaced by WindmillYamlValidator and validate(doc, target).