# Formfire Design Document **Date**: 2026-02-13 **Status**: Approved **Plugin**: obsidian-formfire **Suite**: Fire-Suite (Promptfire = Output, Logfire = Observe, Formfire = Input) ## Problem Obsidian has no native solution for structured data input. Every vault power user reaches a point where they want a form instead of manually typing frontmatter. Existing community solutions (Templater, MetaEdit) solve this only fragmentarily. Formfire closes the Input gap in the Fire-Suite triangle: **Input (Formfire) -> Observe (Logfire) -> Output (Promptfire)**. ## Decisions | Aspect | Decision | |--------|----------| | Form Storage | Plugin Settings | | Output Mode | Both: create new note OR update existing frontmatter | | Access | Command Palette + Sidebar View | | Field Types | Text, Textarea, Number, Toggle, Date, Dropdown, Tags, Note-Link, Folder-Picker, Rating | | Body Template | Yes, with `{{variable}}` substitution | | Form Editor | Visual Form Builder in Settings Tab | | Architecture | A+B Hybrid (pragmatic with clean separation) | ## Data Model ```typescript interface FormDefinition { id: string; // UUID name: string; // "Meeting-Notiz", "Buchrezension" icon: string; // Obsidian icon name mode: "create" | "update"; // mode: "create" only targetFolder?: string; fileNameTemplate?: string; // e.g. "{{datum}}-{{titel}}" bodyTemplate?: string; // Markdown with {{variables}} // mode: "update" only targetFile?: "active" | "prompt"; fields: FormField[]; } interface FormField { id: string; // Unique key (becomes frontmatter property) label: string; // Display name type: FieldType; required: boolean; defaultValue?: any; placeholder?: string; options?: string[]; // For dropdown/tags folder?: string; // For note-link: which folder to search } type FieldType = | "text" | "textarea" | "number" | "toggle" | "date" | "dropdown" | "tags" | "note-link" | "folder-picker" | "rating"; ``` ## Architecture ``` obsidian-formfire/ ├── src/ │ ├── main.ts // Plugin class, commands, view registration │ ├── types.ts // All interfaces │ ├── core/ │ │ ├── form-store.ts // CRUD for FormDefinitions in Settings │ │ └── form-processor.ts // Create note / update frontmatter │ ├── ui/ │ │ ├── settings-tab.ts // Settings tab with form builder │ │ ├── form-builder.ts // Visual form builder (add/edit fields) │ │ ├── form-modal.ts // The form modal for filling out │ │ ├── form-sidebar.ts // Sidebar view with form list │ │ └── field-renderers.ts // Renderer per field type │ └── utils/ │ ├── template-engine.ts // {{variable}} substitution │ └── validators.ts // Field validation ├── styles.css ├── manifest.json ├── package.json ├── tsconfig.json └── esbuild.config.mjs ``` ### Data Flow ``` User opens form (Command/Sidebar) | FormStore loads FormDefinition from Settings | FormModal renders fields via FieldRenderers | User fills out -> Submit | FormProcessor: mode:"create" -> Template Engine -> vault.create() mode:"update" -> processFrontMatter() on active/chosen note ``` ## UI Concept ### A) Settings Tab: Visual Form Builder - **Top**: List of all forms (name, mode, field count) with Add/Edit/Delete/Duplicate buttons - **Bottom / Modal**: Form builder opens on edit with: - Name, Icon, Mode selector (create/update) - Field list with reorder (up/down buttons) - Per field: type dropdown, label, key, required toggle, type-specific options - For create mode: target folder, filename template, body template textarea ### B) Form Modal (for filling out) - Title: form name + icon - Fields rendered vertically by type: - `text` -> Obsidian Setting with text input - `textarea` -> Multi-line text field - `number` -> Number input - `toggle` -> Obsidian Toggle component - `date` -> Native HTML date picker - `dropdown` -> Obsidian Dropdown component - `tags` -> Multi-select with autocomplete (from existing vault tags) - `note-link` -> Text input with vault file suggest - `folder-picker` -> Text input with folder suggest - `rating` -> 5 clickable stars - Bottom: Submit button + validation feedback for required fields - For `mode: "update"` + `targetFile: "prompt"`: File picker first, then form (pre-filled with existing frontmatter values) ### C) Sidebar View - Simple list of all forms with icon + name - Click -> opens FormModal - Gear icon -> opens Settings directly **Note**: Detailed UI will be designed using the frontend-design skill during implementation. ## Commands | Command | Description | |---------|-------------| | `formfire:open-form` | Opens picker modal with all forms, then the chosen FormModal | | `formfire:open-form-` | Dynamically registered commands per form (direct access) | | `formfire:open-sidebar` | Open/focus sidebar view | | `formfire:open-settings` | Jump directly to Formfire settings | **Ribbon Icon**: Form icon in left sidebar, opens form picker. ## Template Engine Intentionally simple: ``` {{fieldname}} -> Value of the field {{date}} -> Current date (YYYY-MM-DD) {{time}} -> Current time (HH:mm) {{datetime}} -> Date + time ``` Used in: - `fileNameTemplate` (filename for new notes) - `bodyTemplate` (markdown content of new notes) ## Out of Scope for V1 - No conditional logic (show field X only if field Y = ...) - No multi-step wizard - No export/import of form definitions - No computed fields - No custom CSS per form - No API for other plugins ## Technical Conventions (from Fire-Suite) - Build: esbuild, ES2022 target - Settings: deep merge pattern (from Logfire) - Plugin lifecycle: standard Obsidian pattern (loadSettings -> register -> start) - Feedback: Obsidian Notice API - File access: vault.create(), processFrontMatter(), metadataCache