The Lossless Group2k downloadsGenerate source-cited research content from Perplexity, Anthropic Claude, Perplexica, or local LM Studio — directly into your notes.

Perplexed is an Obsidian plugin that enables AI-powered content generation with source citations using Perplexity, Anthropic Claude, Google Gemini (with Google Search grounding), and Perplexica / Vane (self-hosted). It also integrates Exa as a retrieval layer — Exa finds and verifies the source material, and the writing model writes from it. This plugin brings research-grade AI capabilities directly into your Obsidian workspace, allowing you to generate well-cited content for your notes.
New in 0.5.0: company profiles can carry verified funding rounds from Fireround, written into the note exactly as they arrived and citeable round by round, alongside what Exa finds. See Funding rounds. Full notes:
changelog/releases/0.5.0.md.
Perplexed ships a set of analyst-grade directory templates aimed at the research deliverables a VC analyst, PE associate, equity-research analyst, or trading-desk strategist produces daily. Drop an empty file into the matching folder, run Apply directory template to current file, and Perplexity Deep Research returns a 6-9K-word cited analyst draft you can curate into a memo for a partner, an IC, or a portfolio review.
| Workflow | Template | What it produces |
|---|---|---|
| Naming the players in a category (incumbents vs challengers vs innovators by financial stage) | market-category-profile.md → concepts/Market-Categories/ |
Three-tier company landscape with explicit definitions: Incumbents (public / late-stage private / PE-owned), Challengers (Series C+ scale-ups, recently public), Innovators (Pre-Seed through Series B). Plus Why Now / What's Happening sections covering CAGR + category-creation momentum, and an Industry Coverage section sub-grouped into Market Reports (Gartner, IDC, Forrester, ABI) / Industry Articles / Financial News (Bloomberg, FT, Pitchbook). |
| Authoring a market map (Known Category or Thesis-Driven) | market-map-profile.md → lost-in-public/market-maps/ |
Analyst-grade memo with 4-8 sub-segments, 20-40 named innovator cards (Offering / Funding / Why-they-matter / Coverage), Market Dynamics (Sizing / Adoption / Capital Flow), Frontier and Open Questions. Anti-incumbent editorial stance prevents big-tech over-representation. |
| Profiling an open spec or standard an investment thesis depends on | standards-and-specs-profile.md → Sources/Standards-and-Specs/ |
Five-way authority typing (de-jure / consortium / vendor-led-open / community / de-facto), three-tier adoption framing with notable holdouts, named editors, stewardship-transition stories, named public critics with their arguments. |
| Catalogue an authoritative source (book, person, channel, report, conference) | source-profile.md → Sources/ |
Type-aware emphasis (author / publisher / cadence / methodology), Google Books URL harvesting for books, signature-work catalog. |
| Encyclopedia entry on a concept, pattern, or mental model the desk repeatedly invokes | concept-profile.md → concepts/ |
Definition, usage, history, examples, case studies. Mermaid + LaTeX rendering discipline baked in for diagrams and formulas. |
Every analyst-grade template runs on sonar-deep-research, ships with idle-only timeout safety (request-timeout-ms: 0, per-chunk idle timer at 270s) and a 24,000-token output budget (max-tokens: 24000) — enough for the longest analyst drafts to land without silent mid-document truncation. See Directory Templates below for the full set and the cft-block grammar for tuning your own.

[1]: 2024, Dec 13. What is GRC (Governance, Risk and Compliance) - Metricstream. Published: 2024-05-01 | Updated: 2024-12-13
[2]: 2025, Jun 16. Governance, risk and compliance (GRC): Definitions and resources. Published: 2025-05-27 | Updated: 2025-06-16
[^E1] sources before the writing model starts[^F1], alongside whatever Exa finds## Screenshots, searching only the note's own sitePerplexed contacts these remote services on your behalf when you invoke their respective commands. Nothing is sent automatically — only the prompts you submit through a command modal, and any text you have explicitly selected when invoking selection-based commands.
| Provider | Endpoint | Account | API key |
|---|---|---|---|
| Perplexity | https://api.perplexity.ai/chat/completions, plus https://api.perplexity.ai/v1/agent for image search |
Required | Required (paid) |
| Exa (retrieval only) | https://api.exa.ai/search |
Required (dashboard) | Required (free tier: $20 signup credit + $10/month, no credit card) |
| Fireround, through Firecrawl (retrieval only) | https://api.firecrawl.dev/v2/scrape |
Required (firecrawl.dev) | Required (Firecrawl account) |
| Anthropic Claude | https://api.anthropic.com/v1/messages |
Required | Required (paid) |
| Google Gemini | https://generativelanguage.googleapis.com/v1beta/models/{model}:streamGenerateContent |
Required (AI Studio) | Required (free tier available, no credit card) |
| Perplexica / Vane (install required) | http://localhost:3030/api/search (default; user-configurable) |
Not required | Not required (self-hosted, runs locally) |
| LM Studio | http://localhost:1234/v1/chat/completions (default; user-configurable) |
Not required | Not required (runs locally) |
When Gemini's google_search grounding is enabled, the plugin also issues
follow-up GET requests to vertexaisearch.cloud.google.com/grounding-api-redirect/…
URLs to resolve them to the real source page (so your ### Citations footer
contains durable source URLs rather than short-lived Google redirects). The
follow-up requests go through Obsidian's requestUrl (Node-side), not the
browser fetch — no cross-origin permissions involved, and the request is
strictly URL-resolution, no auth header.
The plugin does not collect telemetry, ship vault content anywhere else, or update itself — Obsidian handles plugin updates through the community plugin directory.
Requires Obsidian 1.13 or later (desktop only). Perplexed 0.3.1 remains available for older Obsidian versions on the releases page.
Download the plugin:
main.js, manifest.json, and styles.cssperplexed inside your vault's plugins folder: <your vault>/.obsidian/plugins/perplexed/Enable in Obsidian:
Every setting below is also reachable from Obsidian's settings search: type "Exa", "system prompt", or "LM Studio endpoint" and jump straight to the row.
Perplexity is a commercial AI service that provides high-quality, source-cited responses.
Get API Key:
Configure in Plugin:
https://api.perplexity.ai/chat/completionsGoogle Gemini is Google's commercial AI service. The google_search grounding tool returns per-segment citation attribution — meaning each cited sentence is mapped back to the specific URL it came from, which becomes the verbatim quote in your ### Citations footer. AI Studio's free tier requires no credit card to get started.
Get API key:
AIza… stringConfigure in plugin:
gemini-flash-latest (always-current Flash, free-tier friendly) — gemini-pro-latest and pinned gemini-2.5-pro / gemini-2.5-flash also availablePerplexica / Vane is a free, open-source AI search engine that you run locally on your own machine. This plugin does not bundle the server or proxy to a hosted instance — you must install and run it yourself before the "Ask Perplexica / Vane" command will work.
Note on naming: The maintainer (
ItzCrazyKns) renamed the open-source self-hosted repo from Perplexica to Vane on 2026-03-09 (commitfeat(app): rename to 'vane'). The old GitHub URLItzCrazyKns/Perplexicaredirects toItzCrazyKns/Vane. A hosted service at perplexica.io remains live under the Perplexica name — that's a separate hosted product, not what you self-install for use with this plugin. The local API surface this plugin talks to (/api/search, focus modes, optimization modes) is unchanged across the rename.
Install Perplexica / Vane locally:
docker-compose setup, configuring SearXNG, and choosing
your local LLM provider (Ollama, LM Studio, OpenAI-compatible
endpoints, etc.).curl http://localhost:3030/api/searchConfigure in this plugin:
http://localhost:3030/api/search)For local AI processing without internet dependency:
Install LM Studio:
Configure in Plugin:
http://localhost:1234/v1/chat/completionsCtrl/Cmd + PQuestion: "What are the latest developments in quantum computing?"
Model: sonar-pro
Citations: Enabled
Recency: Past month
Question: "Analyze the impact of AI on healthcare in the last 5 years"
Model: sonar-deep-research
Citations: Enabled
Recency: Past 5 years
Note: Deep research mode conducts exhaustive analysis across hundreds of sources and may take 30-60 seconds.
Perplexity responses include:
Enhance selected text using Perplexity AI to improve clarity, add details, and make content more comprehensive.
Ctrl/Cmd + POriginal Text:
AI is changing how we work.
Enhanced Text:
Artificial Intelligence (AI) is fundamentally transforming how we work across various industries and sectors. From automating routine tasks to enabling more sophisticated decision-making processes, AI technologies are reshaping traditional workflows and creating new opportunities for productivity and innovation.
Ctrl/Cmd + Pgemini-flash-latest (recommended, free-tier friendly), gemini-pro-latest, or pinned 2.5 versionsgoogle_search tool; emits per-segment citationsgoogle.com/search (Markdown-native substitute for Google's required Search Suggestions chip)vertexaisearch.cloud.google.com grounding-redirect URLs to durable source URLs + real page titles before writing the citations footerGemini's groundingSupports[] carries per-segment attribution that survives the full response round-trip — meaning the ### Citations footer contains the verbatim quote per source, attached to the prose above it. Compare to Claude's web_search_20260209, where the dynamic-filter sandbox post-processes search results and per-claim attachment doesn't survive: text blocks come back with citations: null.
The plugin walks two layers of provenance:
| Layer | Field | What it gives you |
|---|---|---|
| Page-level | groundingChunks[] |
URL + title per page Gemini consulted |
| Segment-level | groundingSupports[] |
Text span (segment.text) → indices into groundingChunks[] |
Page-level chunks become URL-and-title fallbacks; segment-level supports enrich them with the verbatim quote Gemini grounded against. Citation footer mirrors Claude's exactly ([N]: [Title](url). > cited_text) so cite-wide's hex-substitution pass works on Gemini output too.
Question: "Who won the 2024 Nobel Prize in Physics and what was the citation?"
Model: gemini-flash-latest
Grounding: Enabled
Resolve URLs: Enabled
Lands in the note with prose like:
The 2024 Nobel Prize in Physics was jointly awarded to John J. Hopfield and Geoffrey Hinton.
The Nobel Prize Committee cited them "for foundational discoveries and inventions that enable machine learning with artificial neural networks".
…followed by a ### Google Searches section listing the queries Gemini issued, and a ### Citations footer where each entry is [N]: [Real Page Title](https://nobelprize.org/…) with the verbatim segment as a blockquote.
Ctrl/Cmd + PQuestion: "What are the current theories about dark matter?"
Focus Mode: academicSearch
Optimization: quality
Question: "Help me write an introduction about climate change"
Focus Mode: writingAssistant
Optimization: balanced
Ctrl/Cmd + PQuestion: "Write a short story about a robot learning to paint"
Model: ibm/granite-3.2-8b
Temperature: 0.8
System Prompt: "You are a creative storyteller who writes engaging narratives."
Question: "Explain how neural networks work"
Model: microsoft/phi-4-reasoning-plus
Temperature: 0.3
System Prompt: "You are a technical expert who explains complex concepts clearly."
| Command | Description | Usage |
|---|---|---|
Ask Perplexity |
Query Perplexity AI with full configuration | Editor command with modal interface |
Enhance Selected Text with Perplexity |
Enhance selected text using Perplexity AI | Editor command with modal interface |
Update Perplexity URL |
Change Perplexity API endpoint | Settings command |
Show Perplexity Settings |
Display current Perplexity configuration | Debug command |
| Command | Description | Usage |
|---|---|---|
Apply directory template to current file |
Fill, append to, or remake the active note. Offers model, retrieval, and output-mode choices | Palette command with run dialog |
Apply directory template to all files in folder |
Batch-run a template across a folder | Palette command with folder picker |
Stop directory template batch |
Halt a running batch after the current file | Palette command |
Check Exa service status |
Probe the Exa API with a real one-result query | Palette command |
Fetch screenshots from website |
Search the site in the note's url for product screenshots and add them under ## Screenshots, keeping any already there. Falls back to the note's og_image |
Palette command |
Link back to vault notes |
Find unlinked mentions of other vault notes in the active file and convert them, behind a review table | Palette command with review modal |
Output modes. When the active note already has content, the run dialog offers three choices: Append below it (the default), Remake — rewrite it, passing the old draft to the model as explicitly-stale background after snapshotting to Content-Dev/history/ — or Replace, discarding the old draft outright. Remake exists because a research note written in May is wrong by September; it instructs the model that current sources win on conflict and asks it to name the pivot explicitly.
| Command | Description | Usage |
|---|---|---|
Ask Gemini |
Query Google Gemini with Google Search grounding | Editor command with modal interface |
Check Gemini service status |
Report whether the service initialized and the API key is configured | Debug command |
| Command | Description | Usage |
|---|---|---|
Ask Perplexica / Vane |
Query Perplexica / Vane with focus and optimization modes | Editor command with modal interface |
Update Perplexica / Vane URL |
Change Perplexica / Vane API endpoint | Settings command |
Show Perplexica / Vane Settings |
Display current Perplexica / Vane configuration | Debug command |
| Command | Description | Usage |
|---|---|---|
Ask LM Studio |
Query local LM Studio with custom parameters | Editor command with modal interface |
Update LM Studio URL |
Change LM Studio API endpoint | Settings command |
Show LM Studio Settings |
Display current LM Studio configuration | Debug command |
You can set custom keyboard shortcuts for any command:
Per-folder content generation — one template fills a whole category of files.
Originally specced as "prompt outlines"; the shipped paradigm is broader and is called directory templates throughout the code and command palette. Full reference: docs/directory-templates.md. Engineering changelog: changelog/2026-05-10_01.md.
A working Obsidian vault collects categories of files that share a shape — concepts, vocabulary terms, sources, tooling profiles. Filling them out one editor-callback at a time is untenable when you have hundreds or thousands. A directory template is a single markdown file that says "for any file under concepts/**, here is the structure to fill and the system prompt to use," and the runtime applies it to one file or a whole folder via Perplexity research with streaming writes.
Content-Dev/Templates/ with frontmatter (applies-to-paths glob), a fenced cft config block (provider, model, return flags, system prompt with interpolation tokens like {{basename}} and {{frontmatter.tags}}), and a heading skeleton that becomes the user prompt. Everything below the first *** divider is excluded from the request — it's your scratch space.Apply directory template to current file auto-matches via the glob; Apply directory template to folder runs a batch with a confirmation modal; Stop directory template batch halts a running batch.<think> blocks, swaps [IMAGE N: <description>] markers for real embeds (with a fallback # Images section when the model didn't emit markers but Perplexity returned images), strips unreplaced placeholders, appends a # Sources footer in the format cite-wide can convert to hex citations, appends a separate ## Sources (retrieved) footer when a retrieval stage ran, and stamps cf_last_run + cf_last_run_model into the target's frontmatter.Two peer folders alongside templates/ keep editorial rules vault-visible and DRY:
Content-Dev/
├── templates/ (your seven profile templates)
├── partials/ (reusable snippets included via {{include: name}})
│ ├── mermaid-discipline.md (paired BAD/GOOD examples + 6-item self-check)
│ └── latex-discipline.md (Obsidian MathJax delimiters + $ escaping)
└── preambles/ (auto-attached to every request as system / user messages)
├── inline-citation.md
├── image-placement.md
├── research-framing.md
├── spliced-source-citation.md (attached only when retrieval returned sources)
└── remake-framing.md (attached only on a Remake run)
{{include: name}} in a template body splices in partials/name.md recursively (depth-limited, cycle-detected). Missing files show as inline [[include: name — file not found]] markers so typos stay visible.inline-citation), User preambles (default: image-placement when return-images is on).cft fence: preambles: { system: [...], skip-user: [...], skip-all: true }.Fix the mermaid quoting rule once in partials/mermaid-discipline.md and every future template generation picks it up — no template editing required.
Seven templates ship inlined into the plugin and seed into your vault on first plugin load:
| File | Targets | Use for |
|---|---|---|
concept-profile.md |
concepts/** |
Encyclopedia-style entries on ideas, patterns, mental models. Anti-incumbent editorial stance baked in (tech giants treated as adopters/popularizers, not innovators, unless documented heyday-era origination supports otherwise). Includes both mermaid-discipline and latex-discipline partials. |
vocabulary-profile.md |
Vocabulary/** |
Term definitions with disambiguation through an innovation-consulting lens. |
source-profile.md |
Sources/** |
Profiles of books, people, channels, publications, journals, reports, events — type-aware, with Google Books URL harvesting for books. |
toolkit-profile.md |
Tooling/** |
Profiles of tools, products, platforms, frameworks. |
market-map-profile.md |
lost-in-public/market-maps/**, market-maps/** |
Analyst-grade market-map drafts — both Known Category (e.g., Humanoid Robots) and Thesis-Driven (e.g., Neural Network Hardware as Brains for Robotics). Runs on sonar-deep-research with idle-only timeout, max-tokens: 24000, and a 40-min absolute wall-clock ceiling. |
standards-and-specs-profile.md |
Sources/Standards-and-Specs/**, Standards-and-Specs/** |
Analyst-grade profiles of open specs and standards. Five-way authority typing (de-jure / consortium / vendor-led-open / community / de-facto). Three-tier structural adoption framing (incumbents / challengers / innovators) plus notable holdouts. Named editors, stewardship transitions, named critics. |
market-category-profile.md |
concepts/Market-Categories/**, Market-Categories/** |
Concept-folder reference card for a named market category. Three-tier company landscape with explicit FINANCIAL-STAGE definitions: Incumbents (public / late-stage private / PE-owned) → Challengers (Series C+ scale-ups, recently public) → Innovators (Pre-Seed through Series B). Separate Why Now / What's Happening sections covering CAGR + category-creation momentum. Industry Coverage sub-grouped into Market Reports / Industry Articles / Financial News. |
The first four templates use Perplexity's sonar-pro. The three deep-research templates (market-map-profile, standards-and-specs-profile, market-category-profile) use sonar-deep-research and declare per-template cft-block overrides for the wall-clock ceiling (request-timeout-ms), the per-chunk idle timer (stream-idle-timeout-ms), and the Perplexity output-token budget (max-tokens: 24000). See docs/directory-templates.md for the full cft-block grammar and the diagnostic table for distinguishing wall-clock-timeout truncation from max_tokens truncation.
Perplexity writes well and retrieves badly on companies. So it no longer does both jobs.
Ask a grounded search model about NATS — the messaging system — and it will cite the UK's National Air Traffic Services. Ask about Kestra and you get a medical device maker and a financial advisory firm. The prose is excellent; the company is wrong.
Exa is built for the other half of the job. Declare an include-sources: block in a template's cft fence and Exa runs before the writing model, finds the actual entity, and hands over structured facts it can trust.
include-sources:
- provider: exa
query: "{{basename}} {{url}} overview product funding customers"
category: company
num-results: 6
pin: entity
contents:
summary:
query: "What does this do, founded when, funding raised, notable customers?"
schema:
type: object
properties:
founded_year: { type: string }
funding: { type: string }
notable_customers: { type: array, items: { type: string } }
What reaches the prompt:
### Funding rounds — Fireround
**A funding table a search model pieced together can be wrong in ways that look right. Fireround's rounds are checked against their sources first.**
[Fireround](https://fireround.dev) is a verified feed of startup funding rounds, served through Firecrawl. It runs beside Exa, not instead of it. Add it to `include-sources:` and choose the Firecrawl key under **Settings → Perplexed → Firecrawl**:
```yaml
include-sources:
- provider: fireround
write-json-under: "Fundraising History"
- provider: exa
query: "{{basename}} {{url}} overview product funding customers"
Two things happen for a note whose url is a company homepage:
[^F1], [^F2] source, with its amount, date, investors, and announcement link, so each row of a funding table can carry a citation.write-json-under, the plugin itself writes Fireround's records as a json code fence directly under that heading. The model never retypes them, so the numbers arrive verbatim. A later run replaces the fence rather than adding another.It stays out of the way when it should:
openai.com/sora or huggingface.co/some-org/some-model is about something hosted on that domain, and the host's rounds aren't its rounds. Fireround is skipped, and a notice says why.The shipped Toolkit template has the Fireround entry commented out, because it needs a Firecrawl key. Uncomment it to use it.
founded_year: 2017 funding: USD 41,200,000 total funding across multiple rounds (Seed, Venture, Series B) notable_customers: [NVIDIA, Mastercard, Rivian, Replit] workforce: { total: 44 }
#### `pin:` is the precision knob
| Mode | Behaviour | Use for |
|---|---|---|
| `pin: entity` | Restricts the search to the target file's own `url:` domain | Profiling **one** company — `Tooling/**` |
| `pin: none` | Unpinned similarity search across the category | Enumerating **competitors** — market maps |
Unpinned, a NATS query returns Nstream, Element and Mio. That is wrong for a product profile and exactly right for a market map — the same knob, turned opposite ways.
> **Pin narrowly or not at all.** Exa matches `includeDomains` by *substring*, so pinning `cresta.com` also matches `alcresta.com` (a pharma company), `codecresta.com`, and `ridgecresta.com`. Perplexed re-checks every result against the real hostname, so impostors are dropped before they reach the prompt — but do not hand it broad domains like `github.com`, which will always surface something.
#### Retrieved sources get their own citation namespace
The writing model numbers its own web-search citations `[1]`, `[2]`. Retrieved sources are **not** in that array, so they are cited `[^E1]`, `[^E2]` and listed in a separate footer:
```markdown
## Sources (retrieved)
[^F1]: 2019, Sep 10. [PR Newswire](https://www.prnewswire.com/). [Samsara raises $300 million in new growth capital](https://www.prnewswire.com/news-releases/samsara-raises-300-million-300915131.html). Generated: 2026, Nov 01. [Fireround](https://fireround.dev) API response.
[^E1]: [samsara.com](https://www.samsara.com/). [Samsara](https://www.samsara.com/). Generated: 2026, Nov 01. [Exa.ai](https://exa.ai) API response.
Each citation is built from what the provider returned, with no cleanup needed: the published date, the publisher, the page's own headline, the date it was updated if that differs, the date the citation was generated, and the provider that reported it. The model's own Perplexity sources in # Sources use the same format under their [1] numbers. Tracking parameters like utm_* are removed from links. Anything a provider didn't supply is left out. Publishers without a known name appear as their domain, and a company's own site appears as the company. The list in the prompt is context only: if a model repeats it, Perplexed removes the repeat and keeps any prose the model wrote.
If the two namespaces were merged, a fact retrieved from Exa would be footnoted to whatever the search model's third result happened to be — a note that looks perfectly well-cited and attributes claims to the wrong documents. The [^E…] form is a real Obsidian footnote, so hover-preview and click-to-jump work, and cite-wide's spacing pass handles it unchanged.
include-sources: run as if Exa did not exist.$7 per 1,000 searches and $1 per 1,000 pages per content type, so a typical profile is about $0.023. The free tier is $20 in signup credits plus $10 monthly, no credit card.
The real ceiling is context, not money: past roughly 12,000 characters of pasted source text the writing model's attention drifts off your section outline and onto the sources. Perplexed enforces a character budget (Settings → Spliced context budget), drops the lowest-ranked sources when it is exceeded, and leaves a visible marker saying how many — never a silent truncation.
toolkit-profile.md ships with retrieval enabled as the reference implementation.
On first plugin load, Perplexed writes the four templates plus a user-facing README.md to Content-Dev/Templates/ in your vault. The seeder uses a two-tier policy:
A Re-seed templates button in Settings → Directory templates writes any shipped file whose filename doesn't already exist — useful for pulling in a new template after a plugin update without overwriting your edits.
Copy any shipped template under a new filename, change the frontmatter (title, description, applies-to-paths glob), rewrite the cft block's system: prompt for your domain, and rewrite the heading skeleton with the structure you want. Save in Content-Dev/Templates/. The plugin picks it up on the next palette invocation — no reload needed.
For interpolation tokens, the full cft block grammar, the cleanup pipeline mechanics, the editorial stance rationale, frontmatter stamps, and known limits — see docs/directory-templates.md.
0.5.1 — 2026-11-01 · requires Obsidian 1.13
Updated:, Generated:, then the provider.Retrieved sources list stays out of the note, and tracking parameters come off links.changelog/releases/0.5.1.md.0.5.0 — 2026-11-01 · requires Obsidian 1.13
include-sources:: each funding round becomes a citeable [^F1] source, and write-json-under writes the raw data under a heading you name.changelog/releases/0.5.0.md.0.4.0 — 2026-10-06 · requires Obsidian 1.13
changelog/releases/0.4.0.md.0.3.1 — 2026-07-06 · Perplexity streaming restored after a CORS change. Notes.
perplexed-plugin/ # the folder name in your vault must be the plugin id: perplexed
├── main.ts # Plugin class: loads settings, wires services, registers commands
├── src/
│ ├── settings/ # Settings shape, defaults, and the declarative settings tab
│ ├── services/ # One service per provider (Perplexity, Claude, Gemini, ...), plus
│ │ # directory templates, Exa retrieval, vault linking, find images
│ ├── modals/ # The command dialogs
│ ├── docs/ # Templates, partials, and preambles seeded into the vault
│ └── styles/ # CSS, bundled into styles.css
├── tests/ # node:test specs, run against a stub of the obsidian module
├── scripts/run-tests.mjs # Bundles and runs the tests (no test framework)
├── esbuild.config.mjs # Builds main.js and styles.css
├── manifest.json # Plugin id, version, minAppVersion
└── versions.json # Plugin version -> minimum Obsidian version
Requires Node.js 22 and pnpm.
git clone https://github.com/lossless-group/perplexed-plugin.git
cd perplexed-plugin
pnpm install
pnpm dev # esbuild watch: rebuilds main.js and styles.css on change
pnpm test # Node's built-in test runner; no network calls
pnpm build # ESLint (Obsidian's review-bot rules) + tsc + production bundle
To use your working copy in a vault, symlink it into the vault's plugins folder. The link must be named after the plugin id, perplexed:
ln -s /path/to/perplexed-plugin /path/to/your-vault/.obsidian/plugins/perplexed
On Windows (PowerShell):
New-Item -ItemType SymbolicLink -Path "C:\path\to\your-vault\.obsidian\plugins\perplexed" -Target "C:\path\to\perplexed-plugin"
Then run pnpm dev, and reload the plugin to pick up new builds: toggle it off and on in Community plugins, or quit and reopen Obsidian.
main.ts: the PerplexedPlugin class. onload() loads settings, seeds the shipped templates into the vault if the templates folder is empty, builds one service per provider, adds the settings tab, and registers the commands.src/settings/PerplexedSettings.ts: PerplexedPluginSettings, DEFAULT_SETTINGS, and PerplexedSettingTab. The tab implements getSettingDefinitions() (Obsidian 1.13+), so Obsidian draws and indexes the rows; there is no display(). Controls bind to dot-path keys such as prompts.enhancePrompt through getControlValue / setControlValue.src/services/: the provider services. Streaming Perplexity requests go through Node's https module rather than fetch, because Perplexity's API stopped sending the CORS headers Electron's renderer requires (see 0.3.1). Non-streaming requests use Obsidian's request() / requestUrl().src/modals/: one dialog per command. Each takes the service it needs and the prompts service.Provider services copy their API key and endpoint when they are built. After changing a key or endpoint in settings, run Reinitialize provider services (or reload the plugin).
development.pnpm test, pnpm build (ESLint with zero errors and zero warnings, plus tsc) green.PerplexedPluginSettings and DEFAULT_SETTINGS, then a definition in getSettingDefinitions(). The settings tests check that every control key exists in DEFAULT_SETTINGS.tests/plugin-onload.test.ts lists them all.eslint.config.mjs.Releasing. Bump manifest.json, package.json, and versions.json together (three-part semver), write changelog/releases/<version>.md, and push a tag with no v prefix (for example 0.4.0). .github/workflows/release.yml then builds, attests, and publishes the release with those notes.
API Key Not Working:
Network Errors:
Plugin Not Loading:
Enable debug logging by checking the browser console:
Ctrl/Cmd + Shift + I (Developer Tools)The Lossless Group is a loose collection of individuals and organizations interested in creating winning formulae for using AI and Collaborative Tooling. We consult, invest in startups, run Venture Capital Funds, host Hackathons, build products, write content, and contribute to open source projects.
We are committed to playing on the frontiers of technology and staying curious and engaged.
License: MIT
Author: The Lossless Group
Support: GitHub Issues