fable-dev
Use when working on the Fable codebase — modifying, debugging, or extending any part of the Electron + React creative writing app. Covers architecture, coding conventions, procedural recipes, and navigation guidance. Also use when asking questions about how Fable works internally or when planning a new feature.
Install via CLI (Recommended)
clawhub install openclaw/skills/skills/anoldgh/fable-devFable Development Guide
Fable is a creative-writing desktop app: Electron + React 19 + Vite + TanStack Query + Plate.js frontend, Node.js + SQLite + custom indexed filesystem backend, Google ADK for AI features.
Critical Invariant
Every file can have children, not just folders. FileNode.children exists on ANY node regardless of category. A text document can contain child documents (chapters containing scenes). Never assume only folders have children.
parentId and siblingIndex are computed by buildFileTree() at runtime — never persist them.
Where Does My Code Go?
digraph code_placement {
rankdir=TB;
node [shape=diamond];
"Used by both\nfrontend & backend?" -> "src/shared/" [label="yes"];
"Used by both\nfrontend & backend?" -> "Runs in\nNode.js only?" [label="no"];
"Runs in\nNode.js only?" -> "IPC handler?" [label="yes"];
"Runs in\nNode.js only?" -> "React component\nor hook?" [label="no"];
"IPC handler?" -> "src/backend/handlers/" [label="yes"];
"IPC handler?" -> "src/backend/services/" [label="no"];
"React component\nor hook?" -> "src/frontend/components/" [label="component"];
"React component\nor hook?" -> "src/frontend/hooks/" [label="hook"];
"React component\nor hook?" -> "src/frontend/services/" [label="service/singleton"];
node [shape=box];
"src/shared/" [style=filled, fillcolor="#e8f5e9"];
"src/backend/handlers/" [style=filled, fillcolor="#e3f2fd"];
"src/backend/services/" [style=filled, fillcolor="#e3f2fd"];
"src/frontend/components/" [style=filled, fillcolor="#fff3e0"];
"src/frontend/hooks/" [style=filled, fillcolor="#fff3e0"];
"src/frontend/services/" [style=filled, fillcolor="#fff3e0"];
}
Shared code constraint: src/shared/ must NOT import browser APIs, Node.js APIs, or React.
How Do I Access / Mutate Data?
digraph data_access {
rankdir=TB;
node [shape=diamond];
"Inside React\ncomponent?" -> "Use query hooks" [label="yes"];
"Inside React\ncomponent?" -> "Use queryService\nsingleton" [label="no\n(command, service)"];
"Need to mutate\nfile tree?" -> "queryService.mutations.*\n(optimistic updates)" [label="always"];
"Need to read\nfile content?" -> "readFileContent()\nhelper (cache-first)" [label="preferred"];
node [shape=box];
"Use query hooks" [style=filled, fillcolor="#e8f5e9"];
"Use queryService\nsingleton" [style=filled, fillcolor="#e8f5e9"];
"queryService.mutations.*\n(optimistic updates)" [style=filled, fillcolor="#fff3e0"];
"readFileContent()\nhelper (cache-first)" [style=filled, fillcolor="#fff3e0"];
}
Never call window.api.* directly for tree mutations — always go through queryService.mutations.* which handles optimistic updates and rollback.
Key Directories
Metadata
Not sure this is the right skill?
Describe what you want to build — we'll match you to the best skill from 16,000+ options.
Find the right skillPaste this into your clawhub.json to enable this plugin.
{
"plugins": {
"official-anoldgh-fable-dev": {
"enabled": true,
"auto_update": true
}
}
}