Skip to content

feat(prompts): say what a run-time prompt is asking for and where it goes - #1555

Merged
chhoumann merged 10 commits into
masterfrom
chhoumann/1546-prompt-context-v2
Jul 26, 2026
Merged

feat(prompts): say what a run-time prompt is asking for and where it goes#1555
chhoumann merged 10 commits into
masterfrom
chhoumann/1546-prompt-context-v2

Conversation

@chhoumann

@chhoumann chhoumann commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Closes #1546.

The problem

A choice's run-time prompt was a modal titled with the choice name over one empty box. A Template's title prompt and a Capture's text prompt were pixel-identical, and nothing said where the answer would land.

Before After

Even the choice name only reached the modal by accident. CompleteFormatter.valueHeader was set exclusively by formatFileName(input, choiceName) and never reset, so it leaked from the path pass into the later content pass. Two consequences fell out of that:

  • Capture to active file runs no path pass, so its body prompt was titled a bare Enter value.
  • MacroChoiceEngine passed "", which survives ?? "Enter value", so a macro's Open file prompt had an empty modal title.

The design

Every prompt should answer three things: what am I typing, for which choice, and where does it land. The change gives the formatter a declared per-pass scope plus a run context, and fills three slots from them:

  1. Title = what is being asked.
  2. Context line (new, muted, under the title) = the choice name and the resolved destination.
  3. Placeholder = always names the field.
Text to capture
New capture → Daily/2026-07-26.md
[ Text to add to the note                    ]

Three decisions carry it.

The scope is declared by the caller, never inferred from which format* method ran. formatFileContent is shared by template bodies, capture bodies, quickAddApi.format and the AI agent, so method-derived copy would be a lie in three of those four cases.

The derived title is used only when the answer is provably the whole of what the scope names. Otherwise the choice name stays the title (today's behaviour) and only the placeholder names the field. For a file name format of {{DATE:YYYY-MM-DD}} {{VALUE}}, a title reading "Note title" would invite the user to retype the date. A vague title is not a lie; an authoritative wrong one is.

Paths use the strict rule, because their literals are part of the answer (Daily/{{VALUE}}.md). A capture format is a one-line template whose literals are decoration, so - [ ] {{VALUE}} still asks for exactly "Text to capture" - which matters, because the "Add to task list" toggle rewrites every default capture into that shape.

No new configuration. Author-side overrides ({{VALUE:name}}, |label:) are untouched, and named tokens keep titling themselves with their variable name; they only gain the context line.

Copy

Scope Title (whole answer) Placeholder (whole) Placeholder (partial)
Template file name Note title Title for the new note Part of the new note's title
Capture target Capture target Where to capture to Part of the capture destination
Capture content Text to capture Text to add to the note Part of the text added to the note
Template body Note content Text inserted into the note Part of the text inserted into the note
Folder Folder Folder for the new note Part of the folder path
Template source path Template Path to the template file Part of the template path
Insert after/before Line to find Existing line to anchor the capture to Part of the line to find
Macro "Open file" File to open Path to the file to open Part of the file path

Tradeoffs

  • Title becomes the ask, not the choice name. The choice name is the only string a multi-prompt run repeated on every modal, which is the disorientation the issue reports. It moves to the context line, so hotkey/URI/macro-nested runs (where no picker was ever shown) still see which choice is asking.
  • Draft keys gained a scopeId. Converging titles would otherwise have collapsed the input-draft key across choices: a cancelled "Add book" would pre-fill "Meeting note". It also separates a {{TEMPLATE:}} include's own prompt from its parent's within one run, and fixes the pre-existing collision between two choices sharing a name.
  • The folder-template flow's ephemeral choice got a path-derived id instead of a fresh uuid per run, so its draft key is stable across runs. Namespaced (folder-template:<path>), so it still cannot collide with a persisted choice's uuid.
  • The context line never states something it cannot back. It withholds the destination for template-source-path prompts (the answer picks which template to read), withholds the folder when a disabled folder setting lets the file name format reroute the note, and is pinned to the file actually being created rather than the pre-collision target.
  • Remote/Raycast has no context-line channel, so the line is folded into the header there rather than lost.
  • Suggester modals are untouched. FuzzySuggestModal has no title element, and |label: already drives their placeholder.

Not doing

Known residuals

  • One-page inputs still under-collect a Template's implicit note name when the file-name format toggle is off. Collecting it made the non-interactive CLI guard reject a stock Capture the engine satisfies from the editor selection, and made the one-page form show an empty title field where the selection used to fill it in. Closing it needs the editor selection modelled in preflight for Template choices; that is a separate change, and the sequential prompt (the surface this issue is about) is correct today.
  • A Template whose folder AND file name are both a bare {{VALUE}} prompts once; the title reflects the folder pass, which runs first.

Validation

Reproduced first, in this worktree's own Obsidian 1.13.0 instance: both prompts came up titled with the choice name, empty placeholder, no description.

Verified after, live, across the shapes that stress the rules:

Choice Title Context line Placeholder
Template, file name {{VALUE}} Note title Add book → Books/ Title for the new note
Template, {{DATE}} {{VALUE}} Daily note → Books/ Part of the new note's title
Template, {{VALUE:title}} title Book w/ author → Books/
Capture + "Add to task list" Text to capture Quick task → Daily/2026-07-26.md Text to add to the note
Capture to active file Text to capture Note to self → Work/…/Weekly standup notes.md Text to add to the note
Capture, target Books/{{VALUE}}.md Book log Part of the capture destination

A three-prompt Template run reads: Note title / Add book → Books/, then author / Add book → Books/Dune.md, then rating / Add book → Books/Dune.md.

Long paths are elided in the middle so the file name survives (Work/…/Weekly standup notes.md), with the full path as the hover tooltip. Measured on the running app: 526px on a desktop modal (no clipping), and wrapping to exactly two lines with no clipping at a 300px modal width under the phone-width rules. The wide (multi-line) prompt renders the same line.

pnpm test (3895 passing), pnpm lint, tsc, and pnpm run build are green.

Review

The design and the implementation each went through adversarial review rounds; the reviewers' confirmed findings are folded in, including several that were regressions in my own first attempt:

  • A template body's literals are the note, so one {{VALUE}} in a structured body was enough to title the prompt "Note content".
  • "Append to top/bottom" collisions build their own TemplateInsertEngine, which never received the run context.
  • A {{TEMPLATE:}} include hard-coded the note-body scope, so an include spliced into a file name claimed to ask for note content and offered clipboard-image paste into a path.
  • A phone-width modal clipped the context line, cutting off exactly the destination it exists to show.
  • Apply-template reconciliation reused the applied note's path while asking where the note should move to.

Summary by CodeRabbit

  • New Features
    • Prompt UI can now show an optional “context line” (with tooltip) under prompt titles, including improved mobile wrapping/clamping.
    • Prompt drafts are now more reliably scoped to avoid cross-choice and included-template bleed.
    • Folder-based template “new note from template” choices now keep stable identities across runs.
  • Bug Fixes
    • Capture, template insertion, and reconciliation flows now consistently preserve the correct destination/context and apply improved prompt scoping for note-body and target formatting.
    • Folder-path formatting no longer interleaves prompt-scoped behavior.
  • Tests
    • Updated mocks and added/expanded coverage for prompt-context, prompt-scope, and draft scoping behavior.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR adds prompt scopes and run context across formatters, engines, preflight scanning, input modals, and draft persistence. Prompts derive contextual labels, destinations, and stable draft identifiers, while template and capture flows propagate scope information through nested formatting.

Changes

Prompt Context and Formatting

Layer / File(s) Summary
Prompt scope model and formatter behavior
src/formatters/promptScope.ts, src/formatters/formatter.ts, src/formatters/completeFormatter.ts, src/formatters/*test.ts
Prompt scopes, context lines, scoped {{VALUE}} copy, destination handling, and formatter state restoration are added and tested.
Preflight and prompt modal integration
src/preflight/*, src/types/inputPrompt.ts, src/gui/Generic*Prompt/*, src/gui/promptContextLine.ts, src/styles.css
Preflight scanning passes explicit scopes, and input prompts render context lines while forwarding draft scope identifiers.
Choice and template execution propagation
src/engine/*, src/formatters/captureChoiceFormatter.ts
Choice, capture, template, collision, and insertion flows set prompt context and apply scopes during destination and content formatting.
Scoped draft and choice identity
src/utils/InputPromptDraftStore.*, src/engine/runTemplateFromFolder.*
Draft keys include scope identifiers, and folder template choices receive deterministic IDs derived from template paths.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ChoiceEngine
  participant CompleteFormatter
  participant InputPrompt
  participant DraftStore
  ChoiceEngine->>CompleteFormatter: set prompt scope and run context
  CompleteFormatter->>InputPrompt: build scoped title, placeholder, and destination context
  InputPrompt->>DraftStore: read or write draft using draftScopeId
Loading

Possibly related PRs

Suggested labels: released

Poem

A bunny found prompts in a burrow so bright,
With titles and paths shown in soft UI light.
Drafts wear little scope tags, neat and clear,
Templates know where their answers appear.
“Hop!” says the rabbit, “No blanks left in sight!”

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.47% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the main change to runtime prompts.
Linked Issues check ✅ Passed The changes implement scoped placeholders, destination context, and draft scoping as requested in #1546.
Out of Scope Changes check ✅ Passed The added prompt-scope and draft-scoping changes appear directly tied to the linked prompt UX requirements.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chhoumann/1546-prompt-context-v2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 26, 2026

Copy link
Copy Markdown

Deploying quickadd with  Cloudflare Pages  Cloudflare Pages

Latest commit: b5ea97d
Status: ✅  Deploy successful!
Preview URL: https://09bcfaa1.quickadd.pages.dev
Branch Preview URL: https://chhoumann-1546-prompt-contex.quickadd.pages.dev

View logs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4c0c8ada85

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/engine/TemplateChoiceEngine.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/preflight/collectChoiceRequirements.ts (1)

297-329: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Align template preflight scanning with runtime prompt order.

Runtime resolves the template path before folder and note-title formatting, but this collector scans the title/folder first. A shared anonymous {{VALUE}} therefore gets preflight copy such as “Note title” even when the sequential flow first asks for a template path. Scan the template-path string first, while deferring its literal template-body scan until its runtime-equivalent position, and add a regression test covering shared {{VALUE}} across these scopes.

As per coding guidelines, “**/*.{test,spec}.{ts,tsx}: Add regression coverage for bug fixes.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/preflight/collectChoiceRequirements.ts` around lines 297 - 329, Update
the preflight flow around scanContentWithTemplateIncludes and scanTemplateSource
to match runtime order: scan the template-path string before folder and
note-title formatting, but defer scanning the template body until its
runtime-equivalent position. Add regression coverage in the relevant test file
for a shared anonymous VALUE across template path, folder, and note-title
scopes, verifying the preflight prompt assignment follows runtime order.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/engine/applyTemplateToActiveNote.test.ts`:
- Line 30: Update the setPromptRunContext mock in the applyTemplateToActiveNote
tests to capture its payload, then assert the expected choice/template draft
scope and destination for both choice-backed and bare-template application
paths.

In `@src/engine/templateEngine-title.test.ts`:
- Around line 15-22: Reindent the added mock members in the withPromptScope
setup, including its parameters and callback body, with tabs instead of spaces
to comply with the repository’s formatting conventions; preserve the existing
mock behavior.

---

Outside diff comments:
In `@src/preflight/collectChoiceRequirements.ts`:
- Around line 297-329: Update the preflight flow around
scanContentWithTemplateIncludes and scanTemplateSource to match runtime order:
scan the template-path string before folder and note-title formatting, but defer
scanning the template body until its runtime-equivalent position. Add regression
coverage in the relevant test file for a shared anonymous VALUE across template
path, folder, and note-title scopes, verifying the preflight prompt assignment
follows runtime order.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 92879568-3516-4704-b2fb-d6c943259259

📥 Commits

Reviewing files that changed from the base of the PR and between af70dcb and 4c0c8ad.

📒 Files selected for processing (42)
  • src/engine/CaptureChoiceEngine.audit-capture.test.ts
  • src/engine/CaptureChoiceEngine.heading-picker.test.ts
  • src/engine/CaptureChoiceEngine.merge.test.ts
  • src/engine/CaptureChoiceEngine.notice.test.ts
  • src/engine/CaptureChoiceEngine.selection.test.ts
  • src/engine/CaptureChoiceEngine.ts
  • src/engine/MacroChoiceEngine.ts
  • src/engine/SingleTemplateEngine.ts
  • src/engine/TemplateChoiceEngine.audit-template.test.ts
  • src/engine/TemplateChoiceEngine.collision.test.ts
  • src/engine/TemplateChoiceEngine.discovery.test.ts
  • src/engine/TemplateChoiceEngine.folderSorting.test.ts
  • src/engine/TemplateChoiceEngine.notice.test.ts
  • src/engine/TemplateChoiceEngine.ts
  • src/engine/TemplateEngine.ts
  • src/engine/TemplateInsertEngine.audit-template.test.ts
  • src/engine/TemplateInsertEngine.test.ts
  • src/engine/TemplateInsertEngine.ts
  • src/engine/applyTemplateToActiveNote.test.ts
  • src/engine/applyTemplateToActiveNote.ts
  • src/engine/runTemplateFromFolder.test.ts
  • src/engine/runTemplateFromFolder.ts
  • src/engine/templateEngine-title.test.ts
  • src/formatters/captureChoiceFormatter-clipboard.test.ts
  • src/formatters/captureChoiceFormatter.ts
  • src/formatters/completeFormatter.audit-formatter-core.test.ts
  • src/formatters/completeFormatter.imagePaste.test.ts
  • src/formatters/completeFormatter.promptContext.test.ts
  • src/formatters/completeFormatter.test.ts
  • src/formatters/completeFormatter.ts
  • src/formatters/formatter.ts
  • src/formatters/promptScope.test.ts
  • src/formatters/promptScope.ts
  • src/gui/GenericInputPrompt/GenericInputPrompt.ts
  • src/gui/GenericWideInputPrompt/GenericWideInputPrompt.ts
  • src/gui/promptContextLine.ts
  • src/preflight/RequirementCollector.ts
  • src/preflight/collectChoiceRequirements.ts
  • src/styles.css
  • src/types/inputPrompt.ts
  • src/utils/InputPromptDraftStore.test.ts
  • src/utils/InputPromptDraftStore.ts

Comment thread src/engine/applyTemplateToActiveNote.test.ts Outdated
Comment thread src/engine/templateEngine-title.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/engine/applyTemplateToActiveNote.test.ts`:
- Around line 302-321: Update the test case around applyTemplateToNote to invoke
templates/tpl.md twice before applying templates/other.md, then assert that the
captured draftScopeId values contain two consecutive
"template-insert#templates/tpl.md" entries followed by the distinct
other-template scope. Keep the existing scope collection and ensure the test
directly verifies repeated applications reuse the same scope.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 20fd0aba-0ff1-4261-b217-76102c51f596

📥 Commits

Reviewing files that changed from the base of the PR and between 3638d9c and 5b4198a.

📒 Files selected for processing (1)
  • src/engine/applyTemplateToActiveNote.test.ts

Comment thread src/engine/applyTemplateToActiveNote.test.ts
@chhoumann
chhoumann force-pushed the chhoumann/1546-prompt-context-v2 branch from 74db43b to da720dc Compare July 26, 2026 19:44

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/engine/MacroChoiceEngine.ts`:
- Around line 868-871: Update the Open File handling around
formatter.formatFileName in MacroChoiceEngine to initialize the prompt run
context before formatting command.filePath. Include the choiceName and a stable
draftScopeId derived per command, ensuring multiple Open File commands within
one macro receive distinct stable identifiers while preserving the existing
filePath scope.

In `@src/formatters/promptScope.ts`:
- Around line 228-240: Update elideMiddlePath so long two-segment paths such as
Folder/filename are shortened while preserving the final filename instead of
returning the original path. Adjust the segments.length <= 2 handling to retain
the destination segment and apply the existing elision behavior, while
preserving unchanged results for paths already within maxLength and existing
multi-segment paths.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d7a1e43d-65d6-4472-8ebe-0dac04a4f7de

📥 Commits

Reviewing files that changed from the base of the PR and between 74db43b and da720dc.

📒 Files selected for processing (42)
  • src/engine/CaptureChoiceEngine.audit-capture.test.ts
  • src/engine/CaptureChoiceEngine.heading-picker.test.ts
  • src/engine/CaptureChoiceEngine.merge.test.ts
  • src/engine/CaptureChoiceEngine.notice.test.ts
  • src/engine/CaptureChoiceEngine.selection.test.ts
  • src/engine/CaptureChoiceEngine.ts
  • src/engine/MacroChoiceEngine.ts
  • src/engine/SingleTemplateEngine.ts
  • src/engine/TemplateChoiceEngine.audit-template.test.ts
  • src/engine/TemplateChoiceEngine.collision.test.ts
  • src/engine/TemplateChoiceEngine.discovery.test.ts
  • src/engine/TemplateChoiceEngine.folderSorting.test.ts
  • src/engine/TemplateChoiceEngine.notice.test.ts
  • src/engine/TemplateChoiceEngine.ts
  • src/engine/TemplateEngine.ts
  • src/engine/TemplateInsertEngine.audit-template.test.ts
  • src/engine/TemplateInsertEngine.test.ts
  • src/engine/TemplateInsertEngine.ts
  • src/engine/applyTemplateToActiveNote.test.ts
  • src/engine/applyTemplateToActiveNote.ts
  • src/engine/runTemplateFromFolder.test.ts
  • src/engine/runTemplateFromFolder.ts
  • src/engine/templateEngine-title.test.ts
  • src/formatters/captureChoiceFormatter-clipboard.test.ts
  • src/formatters/captureChoiceFormatter.ts
  • src/formatters/completeFormatter.audit-formatter-core.test.ts
  • src/formatters/completeFormatter.imagePaste.test.ts
  • src/formatters/completeFormatter.promptContext.test.ts
  • src/formatters/completeFormatter.test.ts
  • src/formatters/completeFormatter.ts
  • src/formatters/formatter.ts
  • src/formatters/promptScope.test.ts
  • src/formatters/promptScope.ts
  • src/gui/GenericInputPrompt/GenericInputPrompt.ts
  • src/gui/GenericWideInputPrompt/GenericWideInputPrompt.ts
  • src/gui/promptContextLine.ts
  • src/preflight/RequirementCollector.ts
  • src/preflight/collectChoiceRequirements.ts
  • src/styles.css
  • src/types/inputPrompt.ts
  • src/utils/InputPromptDraftStore.test.ts
  • src/utils/InputPromptDraftStore.ts
🚧 Files skipped from review as they are similar to previous changes (30)
  • src/gui/promptContextLine.ts
  • src/types/inputPrompt.ts
  • src/engine/TemplateInsertEngine.audit-template.test.ts
  • src/formatters/completeFormatter.imagePaste.test.ts
  • src/engine/CaptureChoiceEngine.audit-capture.test.ts
  • src/formatters/captureChoiceFormatter-clipboard.test.ts
  • src/engine/TemplateInsertEngine.test.ts
  • src/engine/CaptureChoiceEngine.notice.test.ts
  • src/gui/GenericWideInputPrompt/GenericWideInputPrompt.ts
  • src/utils/InputPromptDraftStore.ts
  • src/engine/TemplateChoiceEngine.audit-template.test.ts
  • src/engine/runTemplateFromFolder.ts
  • src/engine/SingleTemplateEngine.ts
  • src/engine/CaptureChoiceEngine.selection.test.ts
  • src/formatters/captureChoiceFormatter.ts
  • src/engine/TemplateInsertEngine.ts
  • src/engine/TemplateChoiceEngine.notice.test.ts
  • src/preflight/RequirementCollector.ts
  • src/engine/applyTemplateToActiveNote.test.ts
  • src/engine/TemplateChoiceEngine.discovery.test.ts
  • src/formatters/promptScope.test.ts
  • src/utils/InputPromptDraftStore.test.ts
  • src/formatters/completeFormatter.audit-formatter-core.test.ts
  • src/engine/TemplateChoiceEngine.ts
  • src/engine/applyTemplateToActiveNote.ts
  • src/formatters/completeFormatter.promptContext.test.ts
  • src/formatters/completeFormatter.test.ts
  • src/engine/TemplateEngine.ts
  • src/engine/CaptureChoiceEngine.heading-picker.test.ts
  • src/formatters/completeFormatter.ts

Comment thread src/engine/MacroChoiceEngine.ts
Comment thread src/formatters/promptScope.ts
chhoumann added 10 commits July 26, 2026 21:55
A choice's input prompt was a modal titled with the choice name over a
single empty box. A Template's title prompt and a Capture's text prompt
were pixel-identical, and nothing said where the answer would land
(#1546).

The choice name only ever reached the modal by accident:
`CompleteFormatter.valueHeader` was set exclusively by
`formatFileName(input, choiceName)` and never reset, so it leaked from
the path pass into the later content pass. Capture-to-active-file, which
runs no path pass, got a bare "Enter value"; MacroChoiceEngine passed
"", which survives `?? "Enter value"` and rendered an EMPTY title.

Replace it with a declared per-pass `PromptScopeKind` plus a run context
(which choice, and the destination once resolved):

- title = what is being asked, but ONLY when the answer is provably the
  whole of what the scope names. Paths use the strict rule (their
  literals are part of the answer); content scopes tolerate literal
  decoration, so `- [ ] {{VALUE}}` still asks for "Text to capture"
  while `{{DATE:YYYY-MM-DD}} {{VALUE}}` keeps the choice name rather
  than inviting the user to retype the date.
- a muted context line under the title: choice name (when it is not
  already the title) and the resolved destination, with long paths
  elided in the middle so the file name survives.
- the placeholder always names the field.

The scope is declared by the caller, never inferred from which format*
method ran: `formatFileContent` is shared by template bodies, capture
bodies, the script API and the AI agent.

Input drafts gain a `scopeId` so converging titles cannot make one
choice's cancelled draft pre-fill another's, and an included
`{{TEMPLATE:}}` prompt cannot inherit its parent's answer. The
folder-template flow's ephemeral choice gets a path-derived id instead
of a fresh uuid, so its draft key is stable across runs.
The line is clipped to one row and long paths are elided in the middle,
so the shortened text was also all the tooltip offered. Carry the
un-elided form alongside it.
…ntext

Five confirmed defects from a review of the change:

- A template BODY's literal text is the note, so one {{VALUE}} in
  `---\nclient: {{VALUE}}\n---\n# Onboarding` was enough to title the
  prompt "Note content" while it was really asking for a client name.
  Only a capture format keeps the relaxed rule; its literals really are
  one line of decoration.
- "Append to top/bottom" collisions build their own TemplateInsertEngine
  (own formatter), which never received the run context: every prompt
  raised while appending fell back to "Enter value" with no context line
  and an unscoped draft key.
- Apply-template reconciliation reused the applied note's path as the
  destination while asking where the note should MOVE to.
- A phone-width modal clipped the context line, cutting off exactly the
  destination the line exists to show. It now wraps to two lines there,
  and the hover tooltip is always set rather than only when the path was
  elided.
- One-page inputs labelled the same field "Enter value" while the
  sequential prompt called it "Note title"; the preflight collector now
  shares the same scope-derived copy.
- Preflight only scanned a Template's file-name format when the toggle
  was on, but the engine resolves a disabled format to {{VALUE}} anyway.
  The one-page form therefore described the note TITLE using whatever
  the template body said, contradicting the sequential prompt. It now
  scans the effective format (and the same for a disabled capture
  format), which also makes the implicit note-name prompt visible to the
  non-interactive CLI guard for the first time.
- A {{TEMPLATE:}} include renders through its own formatter, which
  hard-coded the note-body scope: an include spliced into a file name
  claimed to be asking for note content, and offered clipboard-image
  paste into a path. It now inherits the including pass's scope, and
  image paste follows the declared sink rather than the pass alone.
- Apply-template set the destination before resolving the template
  SOURCE path, so a token in that path was told it would land in the
  note being templated. The destination is now set after the source
  path resolves.
A prompt inside a template SOURCE path picks which template file to
read, so the note being written is not where that answer lands. The
context line now withholds the destination for that scope (and for the
unknown "generic" scope) instead of each engine having to order its
setPromptRunContext calls around the resolution, which had already been
missed once in Capture's create-with-template path.

Also reverts the preflight "scan the effective format" change from the
previous commit. It was aimed at a label mismatch on the opt-in one-page
surface, but collecting a note-title requirement the engine can satisfy
from the editor selection broke two things: the non-interactive CLI
guard began rejecting a stock Capture that would have captured the
selection, and the one-page form began showing an empty title field
where the selection used to fill it in, so an untouched submit stored ""
and the run died with "File name is empty after formatting". Closing
that properly needs the editor selection modelled in preflight for
Template choices, which is a separate change.
With folder settings off, a formatted name whose first segment is an
existing root folder routes the note from the vault root instead of
Obsidian's default location - and the answer that reroutes it is the one
being typed. The previous guard only caught a literal slash in the
format, so `{{VALUE}}` answered `Projects/Note` (or a global variable
expanding to `Projects/`) still showed the default folder.

shouldTreatFormattedNameAsVaultRelativePath returns false as soon as the
folder is enabled, so "a folder is configured" is exactly the condition
under which the folder shown is guaranteed.
- A macro's Open file command builds its own formatter per command, so a
  {{VALUE}} in that path got no context line and an unscoped draft key.
  It now receives the macro's name and a per-command draft scope, so two
  Open file commands in one macro cannot share a draft.
- elideMiddlePath returned a two-segment path untouched, leaving CSS to
  clip the file name off the end - the opposite of the function's point.
  A single folder is now dropped so the name survives.
@chhoumann
chhoumann force-pushed the chhoumann/1546-prompt-context-v2 branch from 571583a to b5ea97d Compare July 26, 2026 19:56
@chhoumann
chhoumann merged commit 54c312f into master Jul 26, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE REQUEST] Run-time input prompts give no indication of what is being asked or where it goes

1 participant