Rename before community plugin submission (plugin IDs are permanent). Updates plugin ID, display name, package name, all class names, CSS prefix (cc- → pf-), default folders (_claude → _context), built-in target ID, and all documentation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
188 lines
8.6 KiB
Markdown
188 lines
8.6 KiB
Markdown
# Promptfire – Obsidian Plugin
|
||
|
||
## Project overview
|
||
|
||
An Obsidian community plugin that manages and copies vault context to clipboard for use with LLMs. Stores conventions, structure, and rules in a dedicated folder and provides one-hotkey copy with multi-LLM output formatting, prompt templates, frontmatter presets, granular section selection, and context history.
|
||
|
||
- **Entry point**: `src/main.ts` → compiled to `main.js` via esbuild
|
||
- **Release artifacts**: `main.js`, `manifest.json`, `styles.css` (optional)
|
||
- **Plugin ID**: `promptfire`
|
||
- **Desktop only**: `true` (uses Node.js `fs` and `child_process` for external sources)
|
||
|
||
## Environment & tooling
|
||
|
||
- **Runtime**: Obsidian (Electron/Chromium)
|
||
- **Language**: TypeScript (`strict: true`)
|
||
- **Package manager**: npm
|
||
- **Bundler**: esbuild (config in `esbuild.config.mjs`)
|
||
- **Target**: ES2018, CommonJS output
|
||
- **Dependencies**: only `obsidian` (latest) – no external runtime deps
|
||
|
||
### Commands
|
||
|
||
```bash
|
||
npm install # Install dependencies
|
||
npm run dev # Watch mode (incremental, inline sourcemaps)
|
||
npm run build # Type-check + production build (minified, no sourcemaps)
|
||
```
|
||
|
||
### Testing
|
||
|
||
Manual only – copy `main.js`, `manifest.json`, `styles.css` to `<Vault>/.obsidian/plugins/promptfire/`, reload Obsidian, enable plugin.
|
||
|
||
## Source file structure
|
||
|
||
```
|
||
src/
|
||
├── main.ts # Plugin class, command registration, core copy logic
|
||
├── settings.ts # PromptfireSettings interface, defaults, settings tab UI
|
||
├── generator.ts # Context generator modal (vault structure setup wizard)
|
||
├── sources.ts # External context sources (freetext, file, folder, shell)
|
||
├── source-modal.ts # Modal for adding/editing context sources
|
||
├── presets.ts # Frontmatter preset parser & executor (ai-context block)
|
||
├── targets.ts # Multi-target output system (format, truncation, token limits)
|
||
├── target-modal.ts # Modal for adding/editing output targets
|
||
├── templates.ts # Prompt template engine & 5 starter templates
|
||
├── template-modal.ts # Modal for adding/editing templates + import/export
|
||
├── history.ts # Context history manager (save, cleanup, versioning)
|
||
├── history-modal.ts # History viewer modal (browse, diff, restore)
|
||
├── content-selector.ts # Heading/block tree parser for granular selection
|
||
├── file-selector-modal.ts # Modal for selecting files and sections
|
||
├── preview.ts # Preview modal before copying
|
||
```
|
||
|
||
## Plugin commands
|
||
|
||
| ID | Name | Description |
|
||
|----|------|-------------|
|
||
| `copy-context` | Copy context to clipboard | Main command – copies all context files + sources |
|
||
| `copy-context-with-note` | Copy context with current note | Same as above but always includes active note |
|
||
| `copy-context-selective` | Copy context (select sections) | Opens file/heading selector modal |
|
||
| `copy-context-from-preset` | Copy context from frontmatter preset | Reads `ai-context` YAML block from active note |
|
||
| `generate-context` | Generate context files | Opens setup wizard to create initial context folder |
|
||
| `view-history` | View context history | Opens history browser with diff and restore |
|
||
|
||
Ribbon icon: `clipboard-copy` → triggers `copy-context`.
|
||
|
||
## Settings (`PromptfireSettings`)
|
||
|
||
| Setting | Type | Default | Description |
|
||
|---------|------|---------|-------------|
|
||
| `contextFolder` | `string` | `'_context'` | Vault folder containing context `.md` files |
|
||
| `separator` | `string` | `'---'` | Text separator between files in output |
|
||
| `includeFilenames` | `boolean` | `true` | Add `# === filename ===` headers |
|
||
| `showPreview` | `boolean` | `false` | Show preview modal before copying |
|
||
| `includeActiveNote` | `boolean` | `false` | Always append the currently open note |
|
||
| `excludedFiles` | `string[]` | `[]` | Filenames to skip (case-insensitive) |
|
||
| `sources` | `ContextSource[]` | `[]` | External context sources |
|
||
| `showSourceLabels` | `boolean` | `true` | Add position/name labels to source output |
|
||
| `promptTemplates` | `PromptTemplate[]` | `[]` | Prompt templates with placeholders |
|
||
| `defaultTemplateId` | `string \| null` | `null` | Template applied automatically on copy |
|
||
| `history` | `HistorySettings` | see below | History configuration |
|
||
| `targets` | `OutputTarget[]` | `[]` | Multi-LLM output targets |
|
||
| `primaryTargetId` | `string \| null` | `null` | Target that goes to clipboard |
|
||
| `targetOutputFolder` | `string` | `'_context/outputs'` | Folder for secondary target files |
|
||
|
||
### History settings
|
||
|
||
| Setting | Type | Default |
|
||
|---------|------|---------|
|
||
| `enabled` | `boolean` | `false` |
|
||
| `storageFolder` | `string` | `'.context-history'` |
|
||
| `maxEntries` | `number` | `50` |
|
||
| `autoCleanupDays` | `number` | `30` |
|
||
|
||
## Architecture & key modules
|
||
|
||
### Context sources (`sources.ts`)
|
||
|
||
Four source types, each with `position: 'prefix' | 'suffix'`:
|
||
|
||
| Type | Config | Notes |
|
||
|------|--------|-------|
|
||
| `freetext` | `{ content: string }` | Inline text snippets |
|
||
| `file` | `{ path: string }` | External file (absolute path, requires Node.js `fs`) |
|
||
| `folder` | `{ path: string; recursive: boolean; pattern?: string }` | Directory with optional glob filter |
|
||
| `shell` | `{ command: string; args: string[]; cwd?: string; timeout?: number }` | Command output (default timeout 5s, max 1MB) |
|
||
|
||
### Output targets (`targets.ts`)
|
||
|
||
Three built-in targets (can add custom):
|
||
|
||
| Name | Tokens | Format | Strategy |
|
||
|------|--------|--------|----------|
|
||
| Promptfire | 200,000 | `xml` | `summarize-headers` |
|
||
| GPT-4o | 128,000 | `markdown` | `summarize-headers` |
|
||
| Compact (8k) | 8,000 | `plain` | `drop-sections` |
|
||
|
||
**Formats**: `markdown` (default), `xml` (wraps in `<file name="...">` tags), `plain` (strips markdown).
|
||
|
||
**Truncation strategies**: `truncate` (hard cut), `summarize-headers` (keep headers, collapse content), `drop-sections` (remove low-priority sections entirely).
|
||
|
||
**Priority order for truncation**: VAULT.md > context files > conventions > structure > active note > examples/templates.
|
||
|
||
### Prompt templates (`templates.ts`)
|
||
|
||
Handlebars-like engine with variables: `{{context}}`, `{{selection}}`, `{{active_note}}`, `{{active_note_name}}`, `{{date}}`, `{{time}}`, `{{datetime}}`, `{{vault_name}}`. Supports `{{#if var}}...{{else}}...{{/if}}` conditionals.
|
||
|
||
Five starter templates: Code Review, Summary, Q&A, Continue Writing, Explain.
|
||
|
||
### Frontmatter presets (`presets.ts`)
|
||
|
||
Reads `ai-context` YAML block from the active note's frontmatter:
|
||
|
||
```yaml
|
||
ai-context:
|
||
template: "Template Name"
|
||
include-linked: true
|
||
link-depth: 2 # 0-10
|
||
include-tags: [tag1]
|
||
exclude-paths: [archive/]
|
||
exclude-tags: [draft]
|
||
max-tokens: 50000
|
||
include-active-note: true
|
||
```
|
||
|
||
Features: hierarchical tag matching, link traversal with cycle detection, token budgeting, full validation with errors/warnings.
|
||
|
||
### Content selector (`content-selector.ts`)
|
||
|
||
Parses heading tree (H1–H6) and block IDs (`^blockid`) from markdown files. Enables partial file selection via `FileSelectorModal`. Output marks partial files with `(partial)` suffix.
|
||
|
||
### History (`history.ts`)
|
||
|
||
Stores each generated context as JSON in vault. Tracks metadata: template used, included files/sources, active note, char/token counts, user notes. Auto-cleanup by age and entry count.
|
||
|
||
## Coding conventions
|
||
|
||
- `main.ts` handles plugin lifecycle and command registration – all feature logic lives in dedicated modules.
|
||
- Each module exports its types/interfaces alongside implementation.
|
||
- Modals are in separate `*-modal.ts` files, business logic in the corresponding `.ts` file.
|
||
- Settings are persisted via `loadData()`/`saveData()` with `Object.assign` merge pattern.
|
||
- VAULT.md is always sorted first in context output.
|
||
- Token estimation: `chars / 4` (rough approximation).
|
||
- No external runtime dependencies – everything bundled into `main.js`.
|
||
- CSS class prefix: `pf-` (e.g. `pf-settings-tabs`, `pf-gen-modal`).
|
||
|
||
## Obsidian plugin conventions
|
||
|
||
- Add commands with stable IDs – never rename after release.
|
||
- Use `this.register*` helpers for cleanup on unload.
|
||
- No network calls without explicit user opt-in and documentation.
|
||
- No telemetry, no remote code execution.
|
||
- Keep `minAppVersion` accurate (`0.15.0` currently).
|
||
- Bump `version` in `manifest.json` (SemVer), update `versions.json`, create GitHub release (tag = version, no `v` prefix).
|
||
|
||
## Manifest (`manifest.json`)
|
||
|
||
```json
|
||
{
|
||
"id": "promptfire",
|
||
"name": "Promptfire",
|
||
"version": "1.0.0",
|
||
"minAppVersion": "0.15.0",
|
||
"description": "Copy vault context files to clipboard with one hotkey for any LLM.",
|
||
"author": "Luca",
|
||
"isDesktopOnly": true
|
||
}
|
||
```
|