lossless-group_perplexed-pl.../docs/directory-templates.md
mpstaton f946973894 feat(release): 0.3.0 — three analyst-grade templates for VC/PE/equities + four infrastructure fixes for deep-research reliability
0.3.0 turns Perplexed into a serious analyst tooling layer for Venture
Capital, Private Equity, and equities-trading workflows. Three new directory
templates produce 6-9K-word cited analyst drafts in a single Perplexity
Deep Research run. Underneath them, four infrastructure fixes turn
deep-research from a brittle "might work" workflow into something you can
put real analyst time behind.

The three new templates: market-map-profile (analyst memo for Known
Category or Thesis-Driven maps), standards-and-specs-profile (open-spec
profiles with five-way authority typing and three-tier adoption framing),
market-category-profile (concept-folder reference card with three
financial-stage tiers — Incumbents / Challengers / Innovators). The four
infrastructure fixes: per-template request-timeout-ms wall-clock override
(yesterday, pressure-relief valve), structural port of per-chunk
idle-timeout discipline from the legacy modal flow into the
directory-template flow (yesterday, structural fix), per-template
max-tokens Perplexity output-budget override (today, fixes silent
clean-truncation when finish_reason=length fires mid-template), and a
strengthened mermaid-discipline partial plus new latex-discipline partial
(today, fixes the 4-of-5 broken-Mermaid rate via paired BAD/GOOD examples
and a six-item pre-emit self-check).

New templates (src/docs/templates/):
- market-map-profile.md — sonar-deep-research, request-timeout-ms 2400000
  (40-min ceiling), max-tokens 24000. Anti-incumbent editorial stance.
- standards-and-specs-profile.md — sonar-deep-research, request-timeout-ms 0
  (idle-only safety), max-tokens 24000. Five-way authority typing, named
  editors, stewardship transitions, named critics.
- market-category-profile.md — sonar-deep-research, request-timeout-ms 0,
  max-tokens 24000. Three-tier financial-stage framing, separate Why Now
  and What's Happening sections, Industry Coverage sub-grouped into
  Market Reports / Industry Articles / Financial News.

Rendering-discipline partials (src/docs/partials/):
- mermaid-discipline.md rewritten — paired BAD/GOOD examples throughout,
  the &amp; escape rule, explicit \n vs <br/> ban, six-item self-check
  before emit, simplify-rather-than-break ethos. Original ~250 tokens
  expanded to ~440.
- latex-discipline.md new — Obsidian MathJax delimiters and \$ escaping
  in prose to avoid accidental inline-math spans.
- concept-profile.md wired in {{include: latex-discipline}} alongside the
  existing {{include: mermaid-discipline}}, placed immediately after the
  "render a mermaid codefence here" instruction so the rules are in scope
  at the moment of generation.

Streaming, timeout, and output-budget infrastructure (src/services/
directoryTemplateService.ts):
- streamPerplexityToFile now races each reader.read() against a fresh
  per-chunk idle timer (270s deep-research, 90s normal — matches the
  legacy modal flow at perplexityService.ts:659). Closes the
  "Wall-clock-timeout cuts off long deep-research streams" issue.
- request-timeout-ms cft override is now the optional absolute wall-clock
  ceiling (belt-and-suspenders backstop on top of the idle timer);
  explicit 0 disables.
- max-tokens cft override added to buildPayload — passes through to
  Perplexity's max_tokens parameter; lifts the silent ~8K-token default
  ceiling that was clean-truncating thorough drafts via finish_reason:
  length.

Documentation (README.md, docs/directory-templates.md):
- README — new top-level section "For Venture Capital, Private Equity, and
  Equities-Trading Workflows" with a five-row table mapping each analyst
  workflow to the template that produces it. Directory Templates section
  updated to seven shipped templates plus the new per-template cft-block
  knobs.
- docs/directory-templates.md — new "Per-template max-tokens override"
  section with the diagnostic table for distinguishing wall-clock-timeout
  truncation (mid-sentence cutoff, no sources footer) from max_tokens
  truncation (clean section-end, full sources footer). The diagnostic
  vocabulary that did not exist before this release.

Seeding (src/services/templateSeederService.ts):
- Registered all three new templates plus the new latex-discipline partial
  so they auto-seed into vaults on first plugin load and appear in
  Re-seed runs.

Version bump (manifest.json, package.json, versions.json):
- 0.2.1 to 0.3.0. minAppVersion unchanged at 1.8.10.

Engineering changelog entries (changelog/):
- 2026-05-26_02.md — the structural idle-timeout port.
- 2026-05-27_01.md — the two new templates, max-tokens override, and
  rendering-discipline partial work. Includes the diagnostic-led
  narrative on the vault-drift bug that caused the 4-of-5 broken-Mermaid
  rate.

Release narratives:
- changelog/releases/0.3.0.md — full marketing-quality release narrative
  with frontmatter, four-audience cascade, three diagnostic-led stories
  (streaming-timeout, max_tokens, rendering-discipline), explicit upgrade
  notes including the vault-drift warning, three deferred items for 0.4.x.
- release-notes/0.3.0.md — prose-only release-page body picked up by the
  release.yml workflow when the 0.3.0 tag is pushed. Tighter cut of the
  same narrative, suited for the GitHub release page.

Context-v stamp:
- context-v/issues/Wall-Clock-Timeout-Cuts-Off-Long-Deep-Research-Streams.md
  marked status: resolved, date_resolved 2026-05-26, with the four open
  items reorganized into "what landed" (3 of 4) and "deferred follow-ups"
  (cross-service audit, settings-pane exposure, deep-research detection
  robustness).

Files changed:
- manifest.json, package.json, versions.json
- README.md, docs/directory-templates.md
- src/services/directoryTemplateService.ts
- src/services/templateSeederService.ts
- src/docs/templates/README.md
- src/docs/templates/concept-profile.md
- src/docs/templates/market-map-profile.md
- src/docs/templates/market-category-profile.md (new)
- src/docs/templates/standards-and-specs-profile.md (new)
- src/docs/partials/mermaid-discipline.md
- src/docs/partials/latex-discipline.md (new)
- changelog/2026-05-26_02.md (new)
- changelog/2026-05-27_01.md (new)
- changelog/releases/0.3.0.md (new)
- release-notes/0.3.0.md (new)
- context-v/issues/Wall-Clock-Timeout-Cuts-Off-Long-Deep-Research-Streams.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 17:41:13 -05:00

310 lines
24 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Directory Templates
**Per-folder content generation for Obsidian vaults — one template fills a category of files.**
This is the long-form reference for Perplexed's directory-template system. For the short summary that lives in your vault after first plugin load, see `<your-vault>/Content-Dev/Templates/README.md` (auto-seeded from `src/docs/templates/README.md`). For the engineering changelog that introduced the feature, see [`changelog/2026-05-10_01.md`](../changelog/2026-05-10_01.md).
> The feature was originally specced as "prompt outlines" (see `context-v/specs/Using-Files-as-Prompt-Outlines.md`). The shipped naming — "directory templates" — reflects the eventual scope: it's not just an outline you point at a prompt, it's a template *bound to a directory* via a glob, with auto-seeding, frontmatter stamps, image embedding, and citation hygiene baked into the runtime.
---
## Why this exists
A working Obsidian vault collects categories of files that share a shape — concepts, vocabulary terms, sources, tooling profiles. The pre-template Perplexed flow had one mega-command per content type, each hand-tuned, each running on whichever file you happened to have open. Filling out 1,600 nearly-empty tool profiles in `Tooling/`, several hundred concepts in `concepts/`, the vocabulary, the source profiles, one editor-callback at a time, is untenable.
Directory templates close the gap. The paradigm has three primitives:
1. **A template** — a markdown file in your `Content-Dev/Templates/` folder, with frontmatter that says *which paths it applies to* via a glob (`concepts/**`), a fenced `cft` configuration block, and a heading skeleton that tells the model what to write.
2. **A runtime** — two commands (`Apply directory template to current file`, `Apply directory template to folder`) match the template to a target via the glob, build a streaming request, and write the response back as it arrives.
3. **A cleanup pipeline** — after the stream completes, the runtime wraps `<think>` blocks, swaps `[IMAGE N: …]` markers for real embeds (with a fallback `# Images` section when the model didn't emit markers but Perplexity returned images), strips unreplaced placeholder bullets, appends a `# Sources` footer in the format cite-wide can convert to hex citations, and stamps `cf_last_run` and `cf_last_run_model` into the target's frontmatter.
The combination — template + runtime + editorial stance baked into the system prompts — turns a one-file-at-a-time chore into a batched generative pass with auditable provenance.
---
## Anatomy of a template
A template file has three zones:
```markdown
---
title: Concept Profile
applies-to-paths:
- "concepts/**"
description: Encyclopedia-style entry on a concept, pattern, or mental model.
---
# Free-form intro (ignored)
Anything before the cft block is documentation for the human editing
the template. The runtime drops it from the request.
` ` `cft
provider: perplexity
model: sonar-pro
return-citations: true
return-images: true
system: |
You are writing an encyclopedia-style entry about {{basename}}.
Editorial stance:
- Tech giants are adopters/popularizers, not innovators, unless
documented heyday-era origination supports otherwise.
- Cap big tech at 12 of 57 entries in any Examples section.
- Prefer founder interviews, startup origin stories, and
research-lab papers as attribution.
` ` `
# Definition
- One-paragraph definition. Plain language. No marketing prose.
# Origins
- Who originated this concept and when. Cite the founder, paper, or
originating startup, not the company that later popularized it.
- [IMAGE 1: a diagram or screenshot illustrating the concept]
# Examples
- 57 real-world examples. At most 12 from big tech.
***
# User Notes
Anything below the *** divider is excluded from the request.
You can keep your own notes here without polluting the prompt.
```
(In the actual file, `cft` is a real code-fence — the spaces in the example above are a markdown-escape trick for this doc.)
### The three zones
1. **Frontmatter** (between `---` lines at the top) — carries `title`, `applies-to-paths` (array of globs), and an optional `description`. The runtime uses `applies-to-paths` to match a template to a target file.
2. **`cft` block** (a code fence with language `cft`) — YAML carrying `provider`, `model`, optional `search-recency`, `return-citations`, `return-images`, optional `stream-idle-timeout-ms:` and `request-timeout-ms:` (per-template timeout overrides — see *Per-template timeout overrides* below), optional `max-tokens:` (per-template output-token budget — see *Per-template max-tokens override* below), and a multi-line `system:` prompt. Everything **above** the `cft` block is dropped from the request.
3. **Heading skeleton** — the markdown structure between the `cft` block's closing fence and the first `***` divider. This becomes the user prompt. Bullets under each heading are *instructions to the model*, not literal output. Everything **below** the first `***` is excluded from the request.
### Interpolation tokens
These tokens are substituted into the `system:` prompt before the request is sent:
| Token | Resolves to |
|---|---|
| `{{basename}}` | The target file's filename without extension. **Use this for any H1 the template wants the model to emit** — never use the frontmatter `title`, which the user may have customized away from the basename. |
| `{{title}}` | The target file's frontmatter `title` field, or the basename if missing. |
| `{{today}}` | Today's date in `YYYY-MM-DD` form. |
| `{{frontmatter}}` | The whole frontmatter (whitelisted keys only) as YAML, useful for giving the model existing context about the file. |
| `{{frontmatter.<key>}}` or `{{<key>}}` | A specific frontmatter value (string, number, or array joined with commas). |
The interpolation whitelist is configurable in plugin settings (default: `title, og_description, tags, og_image`). Only whitelisted keys are exposed to prompts.
---
## How a run works
### Path matching
When you invoke **Apply directory template to current file**, the runtime walks every template in `Content-Dev/Templates/`, expands each one's `applies-to-paths` globs, and picks the first that matches the active file's vault path. If multiple templates match (overlapping globs), the first-loaded wins — specificity is not ranked. Don't write overlapping patterns.
When you invoke **Apply directory template to folder**, you get a folder picker, then a template picker (defaults to the template whose glob covers the folder), then a confirmation modal with the file count. The runtime iterates each markdown file under the folder and applies the chosen template. **Stop directory template batch** halts an in-flight batch.
### Fill vs. append
- **Fill mode** runs when the target file's body (everything after frontmatter) is empty or whitespace-only. The streamed output replaces the empty body.
- **Append mode** runs when the target file already has content. The streamed output is appended after the existing body, before the sources footer. The intent: re-running a template never destroys prior work, it accretes.
### Streaming + the cleanup pipeline
The streaming primitive is a real `fetch()` SSE connection — Obsidian's `request()` and `requestUrl` both buffer the whole response, which defeats the point. The runtime:
1. **Streams** the response, parses each `data:` chunk, and flushes accumulated text to the file every ~500ms so you see progress. Failures surface within seconds instead of after a 60-second silent wait.
2. **Captures** Perplexity's `search_results` and `images` arrays as they arrive in the SSE metadata.
3. After the stream ends, runs the cleanup pipeline:
- `wrapThinkBlocks` — converts `<think>…</think>` to fenced ` ```think-output` blocks.
- `processContentWithImages` — swaps `[IMAGE N: …]` markers (permissive regex matches `[Image …]`, `[IMAGE …]`, and the markdown-image-shaped `![IMAGE N](…)` variant) for `![desc](image_url)` using the captured `images` array.
- `buildFallbackImagesSection` — if no markers replaced but `images.length > 0`, emit a `# Images` block before the sources footer so images never silently vanish.
- `stripUnreplacedImagePlaceholders` — remove any `[Image embed placeholder …]` lines the model emitted but didn't replace.
- `buildSourcesFooter` — emit `***`, `# Sources`, and `[N]: [Title](URL)` reference definitions in the canonical Lossless format that cite-wide's `REFDEF_NUM_RE` recognises. Run **Convert All Citations to Hex Format** afterward to swap the numeric markers for stable hex IDs.
### Frontmatter stamps
Every successful run stamps three keys into the target's frontmatter via Obsidian's `processFrontMatter`:
| Key | Value | When |
|---|---|---|
| `cf_last_run` | ISO timestamp | Every run |
| `cf_last_run_model` | `Provider model` label (e.g. `Perplexity sonar-pro`) | Every run |
| `google_books_url` | Harvested URL | Only for book-type sources, only when not already present |
These let you query for stale files later (`cf_last_run` older than X), audit which model produced an entry, and skip Google-Books-URL lookups on subsequent runs.
---
## Shipped templates
Five templates ship inlined into `main.js` (via esbuild's `.md` text loader) and are seeded into the user's vault on first plugin load.
| File | Targets | Model | Notes |
|---|---|---|---|
| `concept-profile.md` | `concepts/**` | `sonar-pro` | Encyclopedia-style entries on ideas, patterns, mental models. Anti-incumbent editorial stance baked in. Switched off `sonar-deep-research` because deep-research is unreliable for image return. |
| `vocabulary-profile.md` | `Vocabulary/**` | `sonar-pro` | Term definitions with disambiguation through an innovation-consulting lens. |
| `source-profile.md` | `Sources/**` | `sonar-pro` | Profiles of trusted sources — books, people, channels, publications, journals, reports, events. Type-aware: the system prompt enumerates seven canonical types and the model picks one from frontmatter signals (`youtube_channel_url` → channel, `aliases` → likely book, etc.). Each section has per-type bullet shapes. |
| `toolkit-profile.md` | `Tooling/**` | `sonar-pro` | Profiles of tools, products, platforms, frameworks. |
| `market-map-profile.md` | `lost-in-public/market-maps/**`, `market-maps/**` | `sonar-deep-research` | Analyst-grade market-map drafts. Dual flavor: Known Category (Quantum Computing, Humanoid Robots) or Thesis-Driven (e.g., Neural Network Hardware as Brains for Robotics) traversing adjacent categories. Lean v1, single-stage. Skips image return by design — deep-research's image metadata is unreliable and market-map imagery is generated separately (Ideogram → frontmatter `banner_image` / `portrait_image` / `square_image`). Multi-stage v2 (RAG pre-flight to inject canonical Lossless tools/concepts as context + Claude editorial pass to emit `[[wikilink]]`s) is deferred — see the User Notes zone of the template for the roadmap. |
`source-profile` is the trickiest because `Sources/` is genuinely heterogeneous. The solution is one template, type-conditional content. Books also trigger Google Books URL handling: frontmatter `google_books_url` is used if present, otherwise the model finds it; either way the URL is harvested into frontmatter post-generation via regex, so subsequent runs skip the search.
### The anti-incumbent editorial stance
`concept-profile`, `vocabulary-profile`, and `source-profile` all embed an "editorial stance — attribute innovation correctly" block in their system prompts. The rules:
- Tech giants (Microsoft, Google, Amazon, Apple, Meta, Oracle, Salesforce, post-1990s IBM) are adopters/popularizers, not innovators, unless documented heyday-era origination or a research-lab paper supports innovator framing.
- Origins favor founder / paper / originating-startup attribution.
- "Best Real-World Examples" caps big tech at 12 of 57 entries.
- Case studies prefer narratives of smaller innovators outpacing incumbents.
This is saved as project memory in the parent monorepo so future templates inherit the rule. It's not Perplexity-specific bias — every default LLM corpus leans incumbent because that's where the training-data signal is.
---
## First-run seeder and re-seed
`templateSeederService.ts` bundles the four templates plus the user-facing README into `main.js` at build time, then writes them to the configured templates folder on `onload`. The policy is **two-tier**:
- **README** (`Content-Dev/Templates/README.md`) — always ensured present. If you delete it, the next plugin load writes it back.
- **Templates** — only seeded when the templates folder is missing or contains no non-README markdown. A folder with even one shipped template is treated as user-managed and left alone.
The **Re-seed templates** button in plugin settings (under *Directory templates*) writes any shipped file whose filename doesn't already exist. Use it after a plugin update introduced a new template, without overwriting your edits to existing ones. To force-reset a template to its shipped default, delete the file first, then click Re-seed.
---
## Writing your own template
1. Copy any shipped template under a new filename (`<your-name>-profile.md`).
2. Change the frontmatter — `title`, `description`, and especially `applies-to-paths`.
3. Rewrite the `cft` block's `system:` to your domain. Use `{{basename}}` for any H1 you want the model to emit. Add interpolation tokens (`{{frontmatter.tags}}`, etc.) where prior context should reach the model.
4. Rewrite the heading skeleton with the structure you want. Use bullets to instruct the model. Use `[IMAGE N: <description>]` markers in places where an image would help — set `return-images: true` in the cft block to activate image embedding.
5. Save it in `Content-Dev/Templates/`. The plugin picks it up on the next palette invocation — no reload needed.
Don't write overlapping `applies-to-paths` patterns across templates; the first matched wins and there's no ranking.
---
## Commands
| Command | Behavior |
|---|---|
| **Apply directory template to current file** | Match the active file's path to a template's `applies-to-paths`; fill or append according to file state. |
| **Apply directory template to folder** | Folder picker → template picker → confirmation modal with file count → batch apply. |
| **Stop directory template batch** | Halt an in-flight batch at the current file boundary. |
All three appear in the Obsidian command palette under `Perplexed: …`.
---
## Per-template timeout overrides
The runtime applies **two complementary timers** to every Perplexity stream (see [`directoryTemplateService.ts`](../src/services/directoryTemplateService.ts) `streamPerplexityToFile`):
| Timer | What it does | Default |
|---|---|---|
| **Stream-idle timeout** (per-chunk) | Each `reader.read()` is raced against a fresh timer. As long as bytes keep arriving, the timer is cleared and re-armed — the stream only dies if it goes **quiet** for the idle duration. | `270_000` ms (4.5 min) for deep-research models (matched by `/deep-research/i` against the resolved model name); `90_000` ms (1.5 min) otherwise. Matches the legacy modal flow in `perplexityService.ts:659`. |
| **Wall-clock ceiling** (absolute) | An optional `AbortController` deadline armed once at fetch time. Belt-and-suspenders backstop. | Plugin-level `settings.requestTimeoutMs` (default **30 min**). Set to **0** in settings to disable; the idle timer alone is responsible for safety. |
The idle timer is the primary safety mechanism. It catches the two pathologies that a single wall-clock timer handles poorly:
- **Silently stalled stream** (Perplexity rate-limit, socket close, upstream stall): the idle timer surfaces the failure within `idleMs` seconds rather than making the user wait the full ceiling.
- **Slow-but-healthy stream**: as long as some byte arrives every `idleMs` seconds, the stream completes naturally — it does not get cut off mid-sentence at the ceiling regardless of whether it's still producing.
Templates can override either or both via their `cft` block:
```cft
provider: perplexity
model: sonar-deep-research
stream-idle-timeout-ms: 270000 # per-chunk idle (default already 270s for deep-research)
request-timeout-ms: 2400000 # absolute ceiling (40 min)
system: |
...
```
Override semantics:
- A numeric value or a numeric string both work.
- For `stream-idle-timeout-ms:`: non-positive / non-numeric values fall through to the model-class default (270s deep, 90s normal).
- For `request-timeout-ms:`: an explicit `0` disables the ceiling entirely (idle-only). Non-numeric or missing falls through to `settings.requestTimeoutMs`.
- Overrides apply only to that template's runs.
- The runtime tolerates mid-stream truncation gracefully: a stream killed by either timer leaves a partial draft on disk with `truncated: true` flagged in the result and a Notice telling the user to re-run.
When to override the defaults:
- `sonar-deep-research` on a multi-section analyst template (market maps, in-depth research reports, sector overviews) routinely emits 68K-word bodies. The 270s idle default lets the slow trickle complete naturally — no override needed for the *idle* key in most cases.
- Bump `request-timeout-ms:` (or set to `0`) when you want truly unbounded healthy runs and trust the idle timer to catch stalls.
- Lower `stream-idle-timeout-ms:` for short non-deep-research templates that should fail fast (the 90s default already does this for them).
- Templates that declare a large `include-sources:` block (per the [multi-stage exploration](../context-v/explorations/Multi-Stage-Cooperative-Claude-and-Perplexity-with-RAG.md)) when that feature ships — RAG context inflation adds first-byte latency; consider bumping `stream-idle-timeout-ms:` if first-byte routinely exceeds the default.
Market-map-profile ships with `request-timeout-ms: 2400000` (40 min ceiling) as a safety cap on absolutely-runaway runs; the per-chunk idle timer (270s, inherited) is what actually keeps the stream healthy. Concept, vocabulary, source, and toolkit profiles declare neither key and inherit `settings.requestTimeoutMs` for the ceiling and the 90s idle default — they all finish comfortably under both.
---
## Per-template `max-tokens:` override
Perplexity's default output-token cap silently truncates long analyst-grade templates by ending the stream **cleanly** with `finish_reason: "length"` mid-skeleton. The symptom is hostile: the run looks like a healthy completion (sources footer renders, no Notice, no truncation warning), but the back half of the section skeleton never appears. Default is approximately 8,192 tokens for `sonar-deep-research` (~6,000 English words).
Templates can override the default by declaring `max-tokens:` inside their `cft` block:
```cft
provider: perplexity
model: sonar-deep-research
max-tokens: 24000 # ~18K-word budget
system: |
...
```
Override semantics:
- A numeric value or a numeric string both work; non-positive / non-numeric values are silently ignored and Perplexity's default applies.
- The override is per-template. Other templates continue to use Perplexity's default.
- Perplexity may itself cap the request below your declared `max-tokens:` based on the model's context window minus the prompt length. If you request more than the model can deliver, Perplexity returns the model's actual cap; your override is the ceiling you're willing to accept.
When to bump above the default:
- **Any analyst-grade template that asks for >6K words of body.** `market-map-profile` and `standards-and-specs-profile` both ship with `max-tokens: 24000` for this reason.
- **Templates with deeply nested skeletons** (3+ heading levels) — the model rations its token budget across the skeleton, and a deep skeleton means more sections competing for the same budget.
- **Templates that demand multiple cards per section** (e.g., the three-tier adoption skeleton in `standards-and-specs-profile` with deeper implementation cards). Each card takes ~150-300 tokens; 15-30 cards × 200 tokens = 3,000-6,000 tokens just for the card sections.
**The diagnostic to distinguish max-tokens truncation from wall-clock truncation:**
| Symptom | Cause |
|---|---|
| Mid-sentence cutoff (literally ends with a partial word or trailing punctuation); no sources footer; user sees "stream went idle" or no Notice at all | Wall-clock timer (`request-timeout-ms:` ceiling) or idle timer (`stream-idle-timeout-ms:`) fired during streaming |
| Clean section-end cutoff (last byte is a paragraph break or full sentence); **sources footer renders correctly with all citations**; no Notice | Perplexity `max_tokens` cap; the stream completed cleanly via `finish_reason: "length"` |
The wall-clock and idle timers are streaming-time controls; `max-tokens` is an output-budget control. They are independent — a template can hit either, neither, or both. Set both knobs generously for thorough deep-research templates.
## Settings
`Plugin settings → Directory templates`:
- **Content-Dev folder path** — root for content-development resources (default: `Content-Dev`).
- **Templates folder path** — where templates live (default: `Content-Dev/Templates`).
- **Frontmatter interpolation whitelist** — comma-separated keys exposed to `{{frontmatter.<key>}}` (default: `title, og_description, tags, og_image`).
- **Re-seed templates** — write any shipped template whose filename doesn't exist in the templates folder.
---
## Known limits and open items
(Mirrored from the changelog's *Open Items* section for completeness — see `changelog/2026-05-10_01.md` for the canonical list.)
- **Image quality on abstract concepts.** Perplexity image search keyword-matches against alt text, so it favors marketing heroes over feature/dashboard screenshots even when the latter would be more illustrative. For concept and vocabulary entries with no canonical visual referent, image search often returns nothing useful. Tier-2 mitigations (multimodal re-rank, headless screenshot service, Ideogram-generated illustrations) are deferred.
- **`<think>` block streaming UX.** Raw `<think>…</think>` blocks land in the file during streaming and only get wrapped to a fenced block at the end. A live wrap during streaming would be cleaner.
- **Multi-`cft` per template.** Each template has one `cft` block today. A multi-block template would let a single template define per-section refresh prompts. Unblocked but not designed.
- **Defensive model capture from API response.** The stamped model name comes from the cft config. If Perplexity silently substitutes a different model (rate-limit fallback), we won't reflect that. Capturing the model name from the SSE response and stamping that instead would close the loop.
- **Citation/backlink preservation under cite-wide.** The image-placeholder strip and `[IMAGE N: …]` replacement run on the streamed string before any cite-wide processing. The ordering is consistent today but isn't pre-flight-checked.
---
## See also
- [`changelog/2026-05-10_01.md`](../changelog/2026-05-10_01.md) — the changelog entry that shipped this paradigm, with full *What Was Built / What Changed in Approach / Files Touched* breakdown.
- [`src/docs/templates/README.md`](../src/docs/templates/README.md) — the shorter doc that gets seeded into the user's vault on first plugin load.
- [`context-v/specs/Using-Files-as-Prompt-Outlines.md`](../context-v/specs/Using-Files-as-Prompt-Outlines.md) — the original "outlines" spec sketch (kept as historical context; the shipped naming and shape evolved past this).
- `cite-wide` plugin's `llmCitationParserService.ts` (`REFDEF_NUM_RE`) — the `[N]: [Title](URL)` form the sources footer emits is what cite-wide's *Convert All Citations to Hex Format* command consumes.