Perplexed 0.3.0 — the analyst-grade release: three deep-research templates for VC / PE / equities workflows, and the four infrastructure fixes they needed to ship
0.3.0 turns Perplexed into a serious analyst tooling layer. Three new deep-research templates (market-map, standards-and-specs, market-category) produce 6-9K-word cited analyst drafts in a single run. Underneath them, four infrastructure fixes — a per-template wall-clock override, an idle-timeout structural port, a max_tokens output-budget knob, and a strengthened mermaid + new LaTeX rendering discipline — turn deep-research from a brittle 'might work' workflow into something you can put real analyst time behind.
Why care?
If your work involves naming the actual companies in a market category, mapping who's playing where in an emerging market, or profiling the open specs and protocols an investment thesis depends on — 0.3.0 is the release where Perplexed becomes a serious analyst tooling layer, not just a notes-with-citations plugin.
Three new directory templates do the bulk of the work. Each produces a 6-9K-word cited analyst draft in a single Perplexity Deep Research run. Each was designed for the kind of document a VC analyst, PE associate, or equities-trading desk strategist hands to a partner or IC:
Market-category profiles name the companies in a category, sorted into three explicit financial-stage tiers — Incumbents (public / late-stage private / PE-owned), Challengers (Series C+ scale-ups), Innovators (Pre-Seed through Series B) — with separate Why Now / What's Happening sections covering CAGR and category-creation momentum, and a fully-sourced Industry Coverage section sub-grouped into Market Reports (Gartner, IDC, Forrester) / Industry Articles / Financial News (Bloomberg, FT, Pitchbook).
Market-map drafts produce the analyst memo itself — 4-8 sub-segments, 20-40 named innovator cards with funding stage and lead investor, Market Dynamics with cited sizing data and capital concentration, and a Frontier section with open questions framed as questions.
Standards-and-specs profiles turn an open protocol or convention into a strategic-context document — 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-transition stories, named public critics with their arguments. The framing surfaces exactly what an analyst needs to know: is this protocol surviving its originating vendor, who has it captured, who's working to break the capture.
If you author any directory template that runs on sonar-deep-research, the four infrastructure fixes that made these templates ship reliably matter more than any single template. Each fix solved a class of "deep-research silently produces broken output" failure mode that would otherwise have kept the analyst-grade workflow brittle.
If you ever ran a long template and got a draft cut off mid-sentence, the streaming-timeout refactor fixes that — the timer that decides "is this stream still alive?" is now armed per-chunk, not once per request, so a healthy slow stream completes naturally and a silently-stalled one fails in seconds. If you ever ran a long template and got a draft that looked complete but was missing the back half of the section skeleton, the new max-tokens: override fixes that — Perplexity's default output cap was silently truncating thorough drafts by ending the stream cleanly mid-template. If you've been frustrated that Perplexity-authored Mermaid diagrams come back broken 4-of-5 times, the strengthened mermaid partial (plus a new LaTeX partial for Obsidian MathJax) addresses that — provided your vault's concept-profile.md is wired to include them, which the release notes here will help you verify.
What's new?
zz-cf-lib/
├── templates/
│ ├── concept-profile.md
│ ├── vocabulary-profile.md
│ ├── source-profile.md
│ ├── toolkit-profile.md
│ ├── market-map-profile.md (new in 0.3.0)
│ ├── standards-and-specs-profile.md (new in 0.3.0)
│ └── market-category-profile.md (new in 0.3.0)
├── partials/
│ ├── mermaid-discipline.md (strengthened in 0.3.0 — ~250 → ~440 tokens)
│ └── latex-discipline.md (new in 0.3.0)
└── preambles/
├── inline-citation.md
├── image-placement.md
└── research-framing.md Three new templates, three new cft-block knobs, one new partial, one strengthened partial:
market-map-profile.md— analyst-grade market-map drafts in Known Category (Humanoid Robots, Quantum Computing) or Thesis-Driven (Neural Network Hardware as Brains for Robotics) shape. Matcheslost-in-public/market-maps/**ormarket-maps/**. Ships withsonar-deep-research,request-timeout-ms: 2400000(40-min ceiling),max-tokens: 24000.standards-and-specs-profile.md— open-spec/standard profiles with five-way authority typing and three-tier adoption framing. MatchesSources/Standards-and-Specs/**. Ships withsonar-deep-research,request-timeout-ms: 0(idle-only safety),max-tokens: 24000.market-category-profile.md— concept-folder reference card for a named market category with three financial-stage tiers. Matchesconcepts/Market-Categories/**. Ships withsonar-deep-research,request-timeout-ms: 0,max-tokens: 24000.request-timeout-ms:cft override — per-template absolute wall-clock ceiling that wins over the plugin-level setting. Set to0to disable and rely on idle-only safety.stream-idle-timeout-ms:cft override — per-template per-chunk idle timer (default 270s for deep-research, 90s otherwise). The primary safety mechanism after the structural port from the legacy modal flow.max-tokens:cft override — per-template Perplexity output-token budget override. Lifts the silent ~8K-token default ceiling that was clean-truncating thorough drafts. Both new deep-research templates and the market-map template now declare 24,000.Strengthened
mermaid-discipline.mdpartial — paired BAD/GOOD examples throughout, the&escape rule, explicit\nvs<br/>ban, six-item self-check before emit, simplify-rather-than-break ethos. Existing broader special-character list and shape rules preserved.New
latex-discipline.mdpartial — Obsidian MathJax delimiters ($$...$$for block,$...$for inline, NOT\[...\]/\(...\)), plus\$escaping for literal dollar amounts to avoid accidental inline-math spans.
The plugin-level default request timeout was also bumped from 600,000 ms (10 min) to 1,800,000 ms (30 min). Settings-pane description rewrote to call out the cost framing — "$10-$50 of analyst time per good output is worth waiting for."
The streaming-timeout story — wall-clock to per-chunk idle
The first thing 0.3.0 fixes is also the most invisible. Until 0.2.x, the directory-template runtime armed a single setTimeout(controller.abort, timeoutMs) at fetch time. If the stream took longer than the ceiling, even by one byte, abort. If the stream went silent for 27 of 30 allotted minutes, wait the full 30 anyway before noticing.
We hit both pathologies in the same week. The first real run of market-map-profile on a Humanoid Robots map produced ~7,500 words then cut off mid-sentence at "R" in the Frontier section because the deep-research run legitimately needed longer than the ceiling. Two days later, the first real run of standards-and-specs-profile on the ARM architecture stopped at a clean section break with all 50 citations rendered correctly — and was missing six of fourteen template sections. Same template, two different failure modes, neither one obvious from the output until you knew what to look for.
The fixes ran in two waves:
Wave 1 — pressure-relief valves. Per-template request-timeout-ms: cft override, plugin-level default bumped 10 → 30 min. The market-map template declares 40 min. Bought headroom; didn't fix the structural problem.
Wave 2 — port the idle-timeout discipline from the legacy modal flow. The PerplexityModal flow had moved to per-chunk idle-timeout discipline two iterations ago — each reader.read() raced against a fresh timer; as long as bytes keep arriving, the timer is cleared and re-armed; only a stream that goes quiet for idleMs is killed. The directory-template flow was forked from an earlier iteration and never received the backport. 0.3.0 ports it. The wall-clock timer becomes an optional belt-and-suspenders ceiling; per-chunk idle (270s for deep-research, 90s otherwise) is the primary safety.
The result: healthy slow streams complete naturally regardless of how long they take. Stalled streams fail in seconds, not at the ceiling. Setting request-timeout-ms: 0 in a cft block disables the ceiling entirely and relies on idle-only safety — the recommended setting for the two new analyst-grade templates.
The max_tokens story — when "healthy completion" lies
The second silent failure was different in flavor. The ARM spec-profile run completed cleanly — full sources footer, all 50 citations, no Notice, no truncation flag, clean section-end cutoff. Every diagnostic signal pointed to "healthy completion." Eight of fourteen sections were missing.
The cause: Perplexity's default max_tokens cap (~8,192 tokens, ~6,000 words for sonar-deep-research). The stream completed via finish_reason: "length" — the model self-rationed across the skeleton, ran out of output-token budget, and wrapped up with a clean tail. The plugin's cleanup pipeline saw a clean stream end, rendered the sources footer, stamped frontmatter — exactly as designed for a healthy completion, because from the stream's perspective it WAS a healthy completion.
The fix is a new max-tokens: cft override that passes through to Perplexity's max_tokens parameter. Both new deep-research templates and the market-map template declare max-tokens: 24000 (~18K-word budget). The new section of docs/directory-templates.md includes the diagnostic table operators need to distinguish the two pathologies:
| Symptom | Cause |
| Mid-sentence cutoff (literally ends with a partial word); no sources footer; user sees "stream went idle" or no Notice at all | Wall-clock or idle timer fired during streaming |
| Clean section-end cutoff; sources footer renders correctly with all citations; no Notice | Perplexity max_tokens cap; stream completed via finish_reason: "length" |
The wall-clock, idle, and max-tokens knobs are independent. A template can hit any of them, all of them, or none. The three new templates set all three generously, and the cleanup pipeline behaves correctly for whichever (if any) fires.
The rendering-discipline story — and the vault-drift bug it surfaced
The third silent failure was a model output issue layered on top of a configuration issue. Concept-profile runs were producing broken Mermaid diagrams roughly 4 of 5 times — unquoted multi-word labels with parentheses, bare & characters, \n instead of <br/>, subgraphs with spaces in titles but no quoted display title. Each broken diagram meant another round-trip to Claude to repair before the entry could ship.
The instinctive fix was to strengthen the rendering rules. The bundled mermaid-discipline.md partial already existed and was already pulled into concept-profile via {{include: mermaid-discipline}} — but the existing rules were stated abstractly and didn't include paired BAD/GOOD examples (which is what actually shifts model behavior).
The deeper diagnosis showed the rules weren't the bottleneck at all:
The vault's concept-profile.md had drifted from the bundled source and was missing the {{include: mermaid-discipline}} directive entirely. The model was generating Mermaid with no rendering rules in scope at all. Strengthening the partial wouldn't have changed a thing until the include was wired up in the running prompt.
This is the kind of bug a long-running plugin generates when seeded templates are user-editable and re-seed only fills in MISSING files: as the bundled template improves over time, the vault copy stays frozen at whatever version was originally seeded. The improvements never reach the running prompt.
The 0.3.0 fix is twofold:
mermaid-discipline.mdrewritten with paired BAD/GOOD examples throughout, the&escape rule, the explicit\nvs<br/>ban, a six-item self-check before emit, and a simplify-rather-than-break ethos (no escape hatch like "describe in prose if unsure" — the discipline forces a working diagram with shortened text rather than a broken one with the labels the model wanted).latex-discipline.mdadded as a new partial covering Obsidian MathJax delimiters and$escaping in prose.
Both wired into concept-profile.md in both the bundled source AND the vault copy. If you've been seeding the templates folder before today, run a quick check after upgrading: open Content-Dev/Templates/concept-profile.md and verify it contains both {{include: mermaid-discipline}} and {{include: latex-discipline}} directives in the Defining and Describing section. If they're missing (as they were in our vault), add them manually — the re-seed button won't update files that already exist.
The vault-drift insight generalizes beyond this fix and is filed as a 0.4.x follow-up: any partial or template improvement we ship needs both a bundled-source update AND a manual vault-copy update for users who've already seeded the folder. A "diff and patch user files" mode for re-seed would close the loop properly.
Editorial discipline by template — three different stances on big tech
The three new deep-research templates share a common technical substrate (sonar-deep-research, idle-only timeout, max-tokens 24000, return-images false) and a common structural posture (named entities everywhere, inline citations, anti-padding discipline). Their editorial discipline diverges in ways that matter for analyst output quality:
Market-map caps big tech at 1-of-5-10 in any sub-bucket to counteract training-data bias. The analyst's job is to name the named operators driving the curve, not the incumbents profiting from it.
Standards-and-specs names big tech freely in the Incumbents tier (large dominant implementations) and aggressively in the Innovators tier (where the next extensions come from). Suppression would distort the implementation landscape.
Market-category names big tech as the FIRST move in Incumbents because for a category profile, naming the incumbents IS the work product. Suppression would be lying about what an enterprise buyer sees.
Each template's system prompt states its editorial stance explicitly so a future template-modifier doesn't accidentally copy the wrong one across templates.
Upgrade notes
Vault template drift — the one you have to check by hand. The biggest gotcha in 0.3.0 is the rendering-discipline fix described above. If your Content-Dev/Templates/concept-profile.md was seeded before today, it may be missing the {{include: mermaid-discipline}} and {{include: latex-discipline}} directives — meaning even after upgrading the plugin and getting the strengthened partials in the vault, the running prompt won't include them until you wire the includes into the template manually. The README's Directory Templates section has the placement; insert both directives immediately after the "render a mermaid codefence here" instruction in the Defining and Describing section. Five seconds of editing; saves you from continued 4-of-5 broken Mermaid.
Re-seed pulls in the new templates and the new latex partial. The seven shipped templates plus the two partials are all bundled into main.js. After upgrading to 0.3.0, click Settings → Directory templates → Re-seed templates to write the new files into your vault (the button only adds files whose filenames don't already exist; nothing existing gets overwritten). You'll see market-map-profile.md, standards-and-specs-profile.md, market-category-profile.md appear in your templates folder, and latex-discipline.md appear in your partials folder.
Backward compatibility. All cft-block additions (request-timeout-ms, stream-idle-timeout-ms, max-tokens) are opt-in. Templates that don't declare them inherit sensible defaults. The four pre-0.3.0 templates (concept, vocabulary, source, toolkit) run unchanged.
Plugin-level default request timeout bumped 10 min → 30 min. Visible in Settings → Directory templates → Request timeout (ms). If you had previously set a custom value, it's preserved.
What's deferred
Three follow-ups surfaced during the 0.3.0 work cycle and are worth tracking for 0.4.x:
A
cf_finish_reasonfrontmatter stamp on every template run. Would have made the ARM max-tokens diagnosis instant ("oh,cf_finish_reason: length, that's a max-tokens issue, not a wall-clock issue") instead of an investigation.A "Continue directory template on current file" command. For runs that get cut off by
max_tokensor by user cancellation, a resume command would read the existing body, identify which template sections are present vs missing via skeleton diff, and re-prompt the model with only the missing sections plus a URL-keyed citation merge to keep[N]markers coherent across the two runs.A "diff and patch user files" mode for re-seed. The vault-drift bug we caught today is structural: re-seed only writes missing files, so improvements to bundled templates and partials never reach users who've already seeded the folder. A diff-and-patch mode (with explicit per-file confirmation) would close the loop.
Engineering changelog references
The full work that landed in 0.3.0 is captured across three engineering-changelog entries:
changelog/2026-05-26_01.md— the market-map template + the per-templaterequest-timeout-ms:override + the plugin-level default bump.changelog/2026-05-26_02.md— the structural idle-timeout port fromperplexityService.ts:659-668intostreamPerplexityToFile. Closed the "Wall-clock timeout cuts off long deep-research streams" issue.changelog/2026-05-27_01.md— the two new templates (standards-and-specs, market-category), themax-tokenscft override, the strengthened mermaid + new LaTeX partials.
The 0.2.1 → 0.3.0 commit range will appear in the GitHub release page when this version is tagged.
Compatibility
minAppVersion: 1.8.10 — unchanged from 0.2.1. Desktop-only (isDesktopOnly: true) — unchanged. No new external dependencies; the three new templates and two partials are bundled into main.js at build time.