From dd7e9b4734f0de52c1bbeff16149a953e03d2aac Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Sun, 15 Mar 2026 04:45:36 +0000 Subject: [PATCH 1/5] docs: add nonDottedPaths convention to CLAUDE.md Co-Authored-By: Claude Opus 4.6 (1M context) --- CLAUDE.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 1e768c214234a..b3cdbdb753bdb 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -50,6 +50,28 @@ let { my_prop = $bindable(default_value) }: { my_prop?: string } = $props() 2. **Create a `useMyPropState()` helper** — encapsulate the undefined-handling logic in a reusable function and call it higher in the component tree, so the child component always receives a defined value. +## CLI: `nonDottedPaths` Convention + +The CLI supports two folder/file naming modes controlled by `nonDottedPaths` in `wmill.yaml`: + +| | Dotted (default) | Non-dotted (`nonDottedPaths: true`) | +|---|---|---| +| Flow folders | `name.flow/` | `name__flow/` | +| App folders | `name.app/` | `name__app/` | +| Raw app folders | `name.raw_app/` | `name__raw_app/` | +| Inline scripts | `a.inline_script.ts` | `a.ts` | +| Lock files | `a.inline_script.lock` | `a.lock` | + +**Required pattern**: Every call to `newPathAssigner()` or `extractInlineScripts*()` in CLI code **must** pass the current setting: + +```typescript +newPathAssigner(defaultTs, { skipInlineScriptSuffix: getNonDottedPaths() }) +``` + +Use `getFolderSuffix(type)` for folder suffixes — never hardcode `.flow`/`__flow`. + +Key files: `cli/src/utils/resource_folders.ts` (config), `cli/windmill-utils-internal/src/path-utils/path-assigner.ts` (path generation). + ## Code Navigation `wm-ts-nav` is an AST-aware code navigator. Use **wm-ts-nav** for structural queries — it skips comments/strings and understands symbol boundaries. From 9b34c8f22e94cf28eac2bd88fb8bb48189301acc Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Sun, 15 Mar 2026 04:50:14 +0000 Subject: [PATCH 2/5] docs(cli): update generated skills to use non-dotted path conventions Co-Authored-By: Claude Opus 4.6 (1M context) --- cli/src/guidance/skills.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/src/guidance/skills.ts b/cli/src/guidance/skills.ts index 0417dbb9dfa4b..7698183d0a9c4 100644 --- a/cli/src/guidance/skills.ts +++ b/cli/src/guidance/skills.ts @@ -4236,10 +4236,10 @@ description: MUST use when creating flows. ## CLI Commands -Create a folder ending with \`.flow\` and add a YAML file with the flow definition. -For rawscript modules, use \`!inline path/to/script.ts\` for the content key. +Create a folder ending with \`__flow\` (or \`.flow\` if \`nonDottedPaths\` is false in wmill.yaml) and add a \`flow.yaml\` file with the flow definition. +For rawscript modules, use \`!inline path/to/script.ts\` for the content key. Inline script files should NOT include \`.inline_script.\` in their names (e.g. use \`a.ts\`, not \`a.inline_script.ts\`). After writing, tell the user they can run: -- \`wmill flow generate-locks --yes\` - Generate lock files for the specific flow you modified (e.g. \`wmill flow generate-locks f/my_folder/my_flow.flow --yes\`) +- \`wmill flow generate-locks --yes\` - Generate lock files for the specific flow you modified (e.g. \`wmill flow generate-locks f/my_folder/my_flow__flow --yes\`) - \`wmill sync push\` - Deploy to Windmill Do NOT run these commands yourself. Instead, inform the user that they should run them. @@ -4375,7 +4375,7 @@ This interactive command creates a complete app structure with your choice of fr ## App Structure \`\`\` -my_app.raw_app/ +my_app__raw_app/ ├── AGENTS.md # AI agent instructions (auto-generated) ├── DATATABLES.md # Database schemas (run 'wmill app generate-agents' to refresh) ├── raw_app.yaml # App configuration (summary, path, data settings) From f6269062a286d172a3c30f200e1cae03882f87bf Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Sun, 15 Mar 2026 04:53:07 +0000 Subject: [PATCH 3/5] fix(cli): make generated skills respect nonDottedPaths config Co-Authored-By: Claude Opus 4.6 (1M context) --- CLAUDE.md | 22 ---------------------- cli/src/commands/init/init.ts | 24 ++++++++++++++++++++++++ cli/src/guidance/skills.ts | 8 ++++---- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index b3cdbdb753bdb..1e768c214234a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -50,28 +50,6 @@ let { my_prop = $bindable(default_value) }: { my_prop?: string } = $props() 2. **Create a `useMyPropState()` helper** — encapsulate the undefined-handling logic in a reusable function and call it higher in the component tree, so the child component always receives a defined value. -## CLI: `nonDottedPaths` Convention - -The CLI supports two folder/file naming modes controlled by `nonDottedPaths` in `wmill.yaml`: - -| | Dotted (default) | Non-dotted (`nonDottedPaths: true`) | -|---|---|---| -| Flow folders | `name.flow/` | `name__flow/` | -| App folders | `name.app/` | `name__app/` | -| Raw app folders | `name.raw_app/` | `name__raw_app/` | -| Inline scripts | `a.inline_script.ts` | `a.ts` | -| Lock files | `a.inline_script.lock` | `a.lock` | - -**Required pattern**: Every call to `newPathAssigner()` or `extractInlineScripts*()` in CLI code **must** pass the current setting: - -```typescript -newPathAssigner(defaultTs, { skipInlineScriptSuffix: getNonDottedPaths() }) -``` - -Use `getFolderSuffix(type)` for folder suffixes — never hardcode `.flow`/`__flow`. - -Key files: `cli/src/utils/resource_folders.ts` (config), `cli/windmill-utils-internal/src/path-utils/path-assigner.ts` (path generation). - ## Code Navigation `wm-ts-nav` is an AST-aware code navigator. Use **wm-ts-nav** for structural queries — it skips comments/strings and understands symbol boundaries. diff --git a/cli/src/commands/init/init.ts b/cli/src/commands/init/init.ts index 807f2fb31b22b..5883967b77aad 100644 --- a/cli/src/commands/init/init.ts +++ b/cli/src/commands/init/init.ts @@ -252,6 +252,16 @@ async function initAction(opts: InitOptions) { } } + // Read nonDottedPaths from config to specialize generated skills + let nonDottedPaths = true; // default for new inits + try { + const { readConfigFile } = await import("../../core/conf.ts"); + const config = await readConfigFile(); + nonDottedPaths = config.nonDottedPaths ?? true; + } catch { + // If config can't be read, use default + } + // Create guidance files (AGENTS.md, CLAUDE.md, and Claude skills) try { // Generate skills reference section for AGENTS.md @@ -290,6 +300,20 @@ async function initAction(opts: InitOptions) { let skillContent = SKILL_CONTENT[skill.name]; if (skillContent) { + // Replace placeholders with actual suffixes based on nonDottedPaths + if (nonDottedPaths) { + skillContent = skillContent + .replaceAll("{{FLOW_SUFFIX}}", "__flow") + .replaceAll("{{APP_SUFFIX}}", "__app") + .replaceAll("{{RAW_APP_SUFFIX}}", "__raw_app") + .replaceAll("{{INLINE_SCRIPT_NAMING}}", "Inline script files should NOT include `.inline_script.` in their names (e.g. use `a.ts`, not `a.inline_script.ts`)."); + } else { + skillContent = skillContent + .replaceAll("{{FLOW_SUFFIX}}", ".flow") + .replaceAll("{{APP_SUFFIX}}", ".app") + .replaceAll("{{RAW_APP_SUFFIX}}", ".raw_app") + .replaceAll("{{INLINE_SCRIPT_NAMING}}", "Inline script files use the `.inline_script.` naming convention (e.g. `a.inline_script.ts`)."); + } // Check if this skill has schemas that need to be appended const schemaMappings = SCHEMA_MAPPINGS[skill.name]; if (schemaMappings && schemaMappings.length > 0) { diff --git a/cli/src/guidance/skills.ts b/cli/src/guidance/skills.ts index 7698183d0a9c4..e97d9babe2830 100644 --- a/cli/src/guidance/skills.ts +++ b/cli/src/guidance/skills.ts @@ -4236,10 +4236,10 @@ description: MUST use when creating flows. ## CLI Commands -Create a folder ending with \`__flow\` (or \`.flow\` if \`nonDottedPaths\` is false in wmill.yaml) and add a \`flow.yaml\` file with the flow definition. -For rawscript modules, use \`!inline path/to/script.ts\` for the content key. Inline script files should NOT include \`.inline_script.\` in their names (e.g. use \`a.ts\`, not \`a.inline_script.ts\`). +Create a folder ending with \`{{FLOW_SUFFIX}}\` and add a \`flow.yaml\` file with the flow definition. +For rawscript modules, use \`!inline path/to/script.ts\` for the content key. {{INLINE_SCRIPT_NAMING}} After writing, tell the user they can run: -- \`wmill flow generate-locks --yes\` - Generate lock files for the specific flow you modified (e.g. \`wmill flow generate-locks f/my_folder/my_flow__flow --yes\`) +- \`wmill flow generate-locks --yes\` - Generate lock files for the specific flow you modified (e.g. \`wmill flow generate-locks f/my_folder/my_flow{{FLOW_SUFFIX}} --yes\`) - \`wmill sync push\` - Deploy to Windmill Do NOT run these commands yourself. Instead, inform the user that they should run them. @@ -4375,7 +4375,7 @@ This interactive command creates a complete app structure with your choice of fr ## App Structure \`\`\` -my_app__raw_app/ +my_app{{RAW_APP_SUFFIX}}/ ├── AGENTS.md # AI agent instructions (auto-generated) ├── DATATABLES.md # Database schemas (run 'wmill app generate-agents' to refresh) ├── raw_app.yaml # App configuration (summary, path, data settings) From 8b9f5f62a6c50be8f82600b469a21b6f3c548d95 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Sun, 15 Mar 2026 05:01:06 +0000 Subject: [PATCH 4/5] fix(cli): inject nonDottedPaths placeholders in generate.py for skills.ts Co-Authored-By: Claude Opus 4.6 (1M context) --- system_prompts/generate.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/system_prompts/generate.py b/system_prompts/generate.py index 5bb40a650c93e..fac7d802f33fa 100644 --- a/system_prompts/generate.py +++ b/system_prompts/generate.py @@ -1094,6 +1094,25 @@ def main(): # Generate skills TypeScript export for CLI skills_ts = generate_skills_ts_export(skills, schema_yaml_content) + + # Replace hardcoded path conventions with placeholders for CLI runtime resolution. + # init.ts resolves these based on the nonDottedPaths setting in wmill.yaml. + # (Frontend auto-generated files keep the default dotted conventions.) + skills_ts = (skills_ts + .replace( + "Create a folder ending with \\`.flow\\`" + " and add a YAML file with the flow definition.\n" + "For rawscript modules, use \\`!inline path/to/script.ts\\`" + " for the content key.", + + "Create a folder ending with \\`{{FLOW_SUFFIX}}\\`" + " and add a \\`flow.yaml\\` file with the flow definition.\n" + "For rawscript modules, use \\`!inline path/to/script.ts\\`" + " for the content key. {{INLINE_SCRIPT_NAMING}}" + ) + .replace("my_flow.flow", "my_flow{{FLOW_SUFFIX}}") + .replace("my_app.raw_app/", "my_app{{RAW_APP_SUFFIX}}/") + ) (CLI_GUIDANCE_DIR / "skills.ts").write_text(skills_ts) print(f"\nGenerated files:") From e4dd35c45f1da67a5b5333d5f864936c5f917d24 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Sun, 15 Mar 2026 05:05:07 +0000 Subject: [PATCH 5/5] fix: default system prompts to non-dotted path conventions Co-Authored-By: Claude Opus 4.6 (1M context) --- system_prompts/auto-generated/flow.md | 6 +++--- system_prompts/auto-generated/prompts.ts | 6 +++--- .../auto-generated/skills/raw-app/SKILL.md | 2 +- .../auto-generated/skills/write-flow/SKILL.md | 6 +++--- system_prompts/base/flow-base.md | 6 +++--- system_prompts/base/raw-app.md | 2 +- system_prompts/generate.py | 19 +++++++------------ 7 files changed, 21 insertions(+), 26 deletions(-) diff --git a/system_prompts/auto-generated/flow.md b/system_prompts/auto-generated/flow.md index 8b00ad0a0ce90..855fa62721e04 100644 --- a/system_prompts/auto-generated/flow.md +++ b/system_prompts/auto-generated/flow.md @@ -2,10 +2,10 @@ ## CLI Commands -Create a folder ending with `.flow` and add a YAML file with the flow definition. -For rawscript modules, use `!inline path/to/script.ts` for the content key. +Create a folder ending with `__flow` and add a `flow.yaml` file with the flow definition. +For rawscript modules, use `!inline path/to/script.ts` for the content key. Inline script files should NOT include `.inline_script.` in their names (e.g. use `a.ts`, not `a.inline_script.ts`). After writing, tell the user they can run: -- `wmill flow generate-locks --yes` - Generate lock files for the specific flow you modified (e.g. `wmill flow generate-locks f/my_folder/my_flow.flow --yes`) +- `wmill flow generate-locks --yes` - Generate lock files for the specific flow you modified (e.g. `wmill flow generate-locks f/my_folder/my_flow__flow --yes`) - `wmill sync push` - Deploy to Windmill Do NOT run these commands yourself. Instead, inform the user that they should run them. diff --git a/system_prompts/auto-generated/prompts.ts b/system_prompts/auto-generated/prompts.ts index 7a0e30221536c..63d3a702b8c24 100644 --- a/system_prompts/auto-generated/prompts.ts +++ b/system_prompts/auto-generated/prompts.ts @@ -33,10 +33,10 @@ export const FLOW_BASE = `# Windmill Flow Building Guide ## CLI Commands -Create a folder ending with \`.flow\` and add a YAML file with the flow definition. -For rawscript modules, use \`!inline path/to/script.ts\` for the content key. +Create a folder ending with \`__flow\` and add a \`flow.yaml\` file with the flow definition. +For rawscript modules, use \`!inline path/to/script.ts\` for the content key. Inline script files should NOT include \`.inline_script.\` in their names (e.g. use \`a.ts\`, not \`a.inline_script.ts\`). After writing, tell the user they can run: -- \`wmill flow generate-locks --yes\` - Generate lock files for the specific flow you modified (e.g. \`wmill flow generate-locks f/my_folder/my_flow.flow --yes\`) +- \`wmill flow generate-locks --yes\` - Generate lock files for the specific flow you modified (e.g. \`wmill flow generate-locks f/my_folder/my_flow__flow --yes\`) - \`wmill sync push\` - Deploy to Windmill Do NOT run these commands yourself. Instead, inform the user that they should run them. diff --git a/system_prompts/auto-generated/skills/raw-app/SKILL.md b/system_prompts/auto-generated/skills/raw-app/SKILL.md index 533e5f7c3e42c..fe9d6ecca5566 100644 --- a/system_prompts/auto-generated/skills/raw-app/SKILL.md +++ b/system_prompts/auto-generated/skills/raw-app/SKILL.md @@ -18,7 +18,7 @@ This interactive command creates a complete app structure with your choice of fr ## App Structure ``` -my_app.raw_app/ +my_app__raw_app/ ├── AGENTS.md # AI agent instructions (auto-generated) ├── DATATABLES.md # Database schemas (run 'wmill app generate-agents' to refresh) ├── raw_app.yaml # App configuration (summary, path, data settings) diff --git a/system_prompts/auto-generated/skills/write-flow/SKILL.md b/system_prompts/auto-generated/skills/write-flow/SKILL.md index f844b813bd1fe..3498502b5f55b 100644 --- a/system_prompts/auto-generated/skills/write-flow/SKILL.md +++ b/system_prompts/auto-generated/skills/write-flow/SKILL.md @@ -7,10 +7,10 @@ description: MUST use when creating flows. ## CLI Commands -Create a folder ending with `.flow` and add a YAML file with the flow definition. -For rawscript modules, use `!inline path/to/script.ts` for the content key. +Create a folder ending with `__flow` and add a `flow.yaml` file with the flow definition. +For rawscript modules, use `!inline path/to/script.ts` for the content key. Inline script files should NOT include `.inline_script.` in their names (e.g. use `a.ts`, not `a.inline_script.ts`). After writing, tell the user they can run: -- `wmill flow generate-locks --yes` - Generate lock files for the specific flow you modified (e.g. `wmill flow generate-locks f/my_folder/my_flow.flow --yes`) +- `wmill flow generate-locks --yes` - Generate lock files for the specific flow you modified (e.g. `wmill flow generate-locks f/my_folder/my_flow__flow --yes`) - `wmill sync push` - Deploy to Windmill Do NOT run these commands yourself. Instead, inform the user that they should run them. diff --git a/system_prompts/base/flow-base.md b/system_prompts/base/flow-base.md index 55d4c06b58837..6c02361891125 100644 --- a/system_prompts/base/flow-base.md +++ b/system_prompts/base/flow-base.md @@ -2,10 +2,10 @@ ## CLI Commands -Create a folder ending with `.flow` and add a YAML file with the flow definition. -For rawscript modules, use `!inline path/to/script.ts` for the content key. +Create a folder ending with `__flow` and add a `flow.yaml` file with the flow definition. +For rawscript modules, use `!inline path/to/script.ts` for the content key. Inline script files should NOT include `.inline_script.` in their names (e.g. use `a.ts`, not `a.inline_script.ts`). After writing, tell the user they can run: -- `wmill flow generate-locks --yes` - Generate lock files for the specific flow you modified (e.g. `wmill flow generate-locks f/my_folder/my_flow.flow --yes`) +- `wmill flow generate-locks --yes` - Generate lock files for the specific flow you modified (e.g. `wmill flow generate-locks f/my_folder/my_flow__flow --yes`) - `wmill sync push` - Deploy to Windmill Do NOT run these commands yourself. Instead, inform the user that they should run them. diff --git a/system_prompts/base/raw-app.md b/system_prompts/base/raw-app.md index 5d68232eda1af..7406d2db168db 100644 --- a/system_prompts/base/raw-app.md +++ b/system_prompts/base/raw-app.md @@ -13,7 +13,7 @@ This interactive command creates a complete app structure with your choice of fr ## App Structure ``` -my_app.raw_app/ +my_app__raw_app/ ├── AGENTS.md # AI agent instructions (auto-generated) ├── DATATABLES.md # Database schemas (run 'wmill app generate-agents' to refresh) ├── raw_app.yaml # App configuration (summary, path, data settings) diff --git a/system_prompts/generate.py b/system_prompts/generate.py index fac7d802f33fa..cf57a3cecb5dc 100644 --- a/system_prompts/generate.py +++ b/system_prompts/generate.py @@ -1097,21 +1097,16 @@ def main(): # Replace hardcoded path conventions with placeholders for CLI runtime resolution. # init.ts resolves these based on the nonDottedPaths setting in wmill.yaml. - # (Frontend auto-generated files keep the default dotted conventions.) + # (Frontend auto-generated files keep the default non-dotted conventions.) skills_ts = (skills_ts + .replace("\\`__flow\\`", "\\`{{FLOW_SUFFIX}}\\`") .replace( - "Create a folder ending with \\`.flow\\`" - " and add a YAML file with the flow definition.\n" - "For rawscript modules, use \\`!inline path/to/script.ts\\`" - " for the content key.", - - "Create a folder ending with \\`{{FLOW_SUFFIX}}\\`" - " and add a \\`flow.yaml\\` file with the flow definition.\n" - "For rawscript modules, use \\`!inline path/to/script.ts\\`" - " for the content key. {{INLINE_SCRIPT_NAMING}}" + "Inline script files should NOT include \\`.inline_script.\\`" + " in their names (e.g. use \\`a.ts\\`, not \\`a.inline_script.ts\\`).", + "{{INLINE_SCRIPT_NAMING}}" ) - .replace("my_flow.flow", "my_flow{{FLOW_SUFFIX}}") - .replace("my_app.raw_app/", "my_app{{RAW_APP_SUFFIX}}/") + .replace("my_flow__flow", "my_flow{{FLOW_SUFFIX}}") + .replace("my_app__raw_app/", "my_app{{RAW_APP_SUFFIX}}/") ) (CLI_GUIDANCE_DIR / "skills.ts").write_text(skills_ts)