{"record":{"id":"5a09cb8010488a0d","repo":"windmill-labs/windmill","slug":"write-app-file-only-writes-frontend-files-use-wri","errorCode":null,"errorMessage":"write_app_file only writes frontend files. Use write_app_runnable to set inline backend script content.","messagePattern":"write_app_file only writes frontend files\\. Use write_app_runnable to set inline backend script content\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/lib/components/copilot/chat/global/core.ts","lineNumber":5808,"sourceCode":"\t\t)\n\t}\n\n\ttoolCallbacks.setToolStatus(toolId, {\n\t\tcontent: `Found ${totalMatchCount} match${totalMatchCount === 1 ? '' : 'es'} in ${fileCount} file${\n\t\t\tfileCount === 1 ? '' : 's'\n\t\t}`\n\t})\n\treturn out.join('\\n')\n}\n\nasync function writeAppFile(\n\targs: { path: string; file_path: string; content: string },\n\tctx: WriteDraftCtx\n): Promise<string> {\n\tconst { workspace, toolId, toolCallbacks } = ctx\n\tconst target = resolveAppFileTarget(args.file_path)\n\tif (target.kind !== 'frontend') {\n\t\tthrow new Error(\n\t\t\t`write_app_file only writes frontend files. Use write_app_runnable to set inline backend script content.`\n\t\t)\n\t}\n\tassertNotGeneratedAppFile(target.filePath)\n\n\ttoolCallbacks.setToolStatus(toolId, {\n\t\tcontent: `Writing ${target.filePath} to app \"${args.path}\"...`\n\t})\n\n\tconst { value } = await loadAppDraftValue(args.path, workspace)\n\tvalue.files = { ...value.files, [target.filePath]: args.content }\n\tconst result = await saveAppDraft(workspace, args.path, value)\n\treturn finishAppDraftWrite(result, ctx, () => ({\n\t\tcontent: `Updated ${target.filePath} in app \"${args.path}\"`,\n\t\tmessage: `Updated draft app \"${args.path}\" with frontend file \"${target.filePath}\".`\n\t}))\n}\n","sourceCodeStart":5790,"sourceCodeEnd":5826,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/lib/components/copilot/chat/global/core.ts#L5790-L5826","documentation":"The write_app_file copilot tool can only create/modify frontend files (svelte components and other files in the app's files map). When the target path resolves to a backend runnable (inline script), the tool throws and directs the model to use write_app_runnable instead, because backend code lives in the runnables map, not the files map.","triggerScenarios":"The AI model calls write_app_file with `file_path` that resolveAppFileTarget classifies as backend (e.g. a `.py`/`.ts` runnable path like `backend/script.py` or a runnable key) instead of a frontend file path.","commonSituations":"Model confusion about the app's dual structure (files vs runnables); trying to edit the inline backend script of a runnable via the file-writing tool; misinterpreting the app schema returned by read tools.","solutions":["Call write_app_runnable with the runnable key/path and the script content instead","Re-read the app schema to identify which targets are frontend files vs backend runnables","If the backend code should be a separate file rather than an inline script, restructure the app so the code lives in a frontend-accessible location or a dedicated script"],"exampleFix":"// before\nwrite_app_file({ path: 'f/app_main', file_path: 'backend/process.py', content: 'def run(): ...' })\n// after\nwrite_app_runnable({ path: 'f/app_main', key: 'process', content: 'def run(): ...' })","handlingStrategy":"validation","validationCode":"const target = resolveAppFileTarget(args.file_path)\nif (target.kind !== 'frontend') {\n  // route to write_app_runnable instead\n}","typeGuard":"function isFrontendTarget(t: { kind: string }): t is { kind: 'frontend'; filePath: string } {\n  return t.kind === 'frontend'\n}","tryCatchPattern":"try {\n  await writeAppFile(args)\n} catch (e) {\n  if (e instanceof Error && e.message.includes('write_app_runnable')) {\n    await writeAppRunnable({ path: args.path, key: args.file_path, content: args.content })\n  }\n}","preventionTips":["Read the app's schema first to know which targets are files vs runnables","Keep the model's context updated after each structural change","Route backend-script edits through runnable tools by convention"],"tags":["ai-agent","tool-arguments","app-editing"],"backgroundTag":"wrong-tool-for-target","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}