{"record":{"id":"9d49143cb2a2e693","repo":"paperclipai/paperclip","slug":"refusing-to-overwrite-protected-wiki-control-file","errorCode":null,"errorMessage":"Refusing to overwrite protected wiki control file ${path}; board-managed edits must use the wiki UI.","messagePattern":"Refusing to overwrite protected wiki control file (.+?); board-managed edits must use the wiki UI\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/plugins/plugin-llm-wiki/src/wiki/core.ts","lineNumber":1195,"sourceCode":"    throw new Error(`Wiki path must stay inside AGENTS.md, IDEA.md, raw/, or wiki/: ${path}`);\n  }\n  return trimmed;\n}\n\nfunction assertPagePath(path: string): string {\n  const normalized = assertWikiPath(path);\n  if (normalized !== \"index.md\" && normalized !== \"log.md\" && normalized !== \"WIKI.md\" && normalized !== \"AGENTS.md\" && normalized !== \"IDEA.md\" && !normalized.startsWith(\"wiki/\")) {\n    throw new Error(`Wiki page writes must target AGENTS.md, IDEA.md, or wiki/: ${path}`);\n  }\n  if (!normalized.endsWith(\".md\")) {\n    throw new Error(`Wiki page path must be a markdown file: ${path}`);\n  }\n  return normalized;\n}\n\nfunction assertPageWriteAllowed(path: string, writer: WritePageInput[\"writer\"] = \"agent_tool\"): void {\n  if (writer !== \"board_ui\" && PROTECTED_WIKI_CONTROL_FILES.has(path)) {\n    throw new Error(`Refusing to overwrite protected wiki control file ${path}; board-managed edits must use the wiki UI.`);\n  }\n}\n\nfunction assertRawPath(path: string): string {\n  const normalized = assertWikiPath(path);\n  if (!normalized.startsWith(\"raw/\")) {\n    throw new Error(`Source path must stay inside raw/: ${path}`);\n  }\n  return normalized;\n}\n\nfunction tableName(namespace: string, table: string): string {\n  return `${namespace}.${table}`;\n}\n\nfunction spaceTable(ctx: PluginContext): string {\n  return tableName(ctx.db.namespace, \"wiki_spaces\");\n}","sourceCodeStart":1177,"sourceCodeEnd":1213,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/plugins/plugin-llm-wiki/src/wiki/core.ts#L1177-L1213","documentation":"Thrown by assertPageWriteAllowed when writer is not 'board_ui' and the target path is in PROTECTED_WIKI_CONTROL_FILES (AGENTS.md or IDEA.md). These control files are board-managed; agents and other writers cannot overwrite them directly and must go through the wiki UI flow.","triggerScenarios":"An agent_tool (or any non-board_ui writer) calling writePage against 'AGENTS.md' or 'IDEA.md'.","commonSituations":"Agent trying to self-edit its instructions file; script bulk-updating control files; using the default writer ('agent_tool') for a board-owned file.","solutions":["Route edits to AGENTS.md / IDEA.md through the board UI (writer: 'board_ui').","For agent-authored content, write under wiki/ instead of overwriting the control file.","If an automated board flow is intended, explicitly set writer: 'board_ui' on the call."],"exampleFix":"// before\nawait writePage(ctx, { companyId, path: \"AGENTS.md\", content, writer: \"agent_tool\" });\n\n// after\n// Option A: route through the board UI flow\nawait writePage(ctx, { companyId, path: \"AGENTS.md\", content, writer: \"board_ui\" });\n// Option B: write agent content elsewhere\nawait writePage(ctx, { companyId, path: \"wiki/agent-notes.md\", content, writer: \"agent_tool\" });","handlingStrategy":"type-guard","validationCode":"const PROTECTED = new Set([\"AGENTS.md\", \"IDEA.md\"]);\nfunction assertPageWriteAllowed(path, writer = \"agent_tool\") {\n  if (writer !== \"board_ui\" && PROTECTED.has(path)) {\n    throw new Error(`Refusing to overwrite protected wiki control file ${path}`);\n  }\n}","typeGuard":"function isProtectedControlFile(path) {\n  return PROTECTED.has(String(path).trim().replace(/^\\/+/, \"\"));\n}","tryCatchPattern":"try {\n  await writePage(ctx, { companyId, path, content, writer });\n} catch (err) {\n  if (/protected wiki control file/.test(err.message)) {\n    if (canUseBoardUi) return writePage(ctx, { companyId, path, content, writer: \"board_ui\" });\n    return writePage(ctx, { companyId, path: \"wiki/agent-notes.md\", content, writer: \"agent_tool\" });\n  }\n  throw err;\n}","preventionTips":["Block agents from editing AGENTS.md / IDEA.md in the UI.","Only set writer: 'board_ui' for genuine board flows.","Keep agent-authored content under wiki/."],"tags":["security","authorization","wiki","control-files","paperclip"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}