T-LN3V-transclusion-rendering-in-agent-manager
State: closed/done · Impact: medium · Complexity: medium
A skill body composed from embedded notes shows those embeds as inert pills, because the Agent
Manager’s editor provider implements no loadNote. Everything downstream of that one optional
method is off: the transclusion body widget never mounts, and the hover preview gates itself out.
Implementing it turns an embed into the content it stands for, foldable and badged with the kind of
what it includes.
| Location | Role today |
|---|---|
solutions/determined/experiences/agent-pants/app/composables/useAgentPantsEditorProvider.ts | Implements searchNotes, searchTags (empty), resolveLink and assetUrl (null). No loadNote, no searchHeadings |
solutions/determined/experiences/agent-pants/app/composables/useAgentPantsEditorProvider.ts#agentPantsEditorProvider | resolveLink returns path as the note’s route, /apps/agent-pants/notes/<vault path>, not the vault-relative path |
packages/ts/obsidian-editor/src/plugins/embeds.ts#TransclusionBodyWidget | Renders the embed’s body below the line, loaded through provider.loadNote, depth 1, cached in transclusionCache |
packages/ts/obsidian-editor/src/plugins/embeds.ts#TransclusionPillWidget | The inline pill, and the whole story when the provider cannot load notes |
packages/ts/obsidian-editor/src/types.ts#EditorIndexProvider | loadNote? and searchHeadings? are optional; absent loadNote means embeds stay collapsed |
packages/ts/obsidian-md/src/types.ts#LoadedNote | {body, frontmatterYaml?} — no kind, no icon |
packages/ts/markdown-ui/app/components/MdSurface.vue | showHoverPreview gates on provider.loadNote !== undefined; the surface’s own loadNote resolves null when the provider has none |
packages/ts/markdown-ui/app/components/MdHoverPreview.vue | Self-gates on provider.loadNote and renders nothing without it |
packages/ts/obsidian-editor/src/theme.ts | Styles .cm-transclusion-embed, .cm-transclusion-pill and .cm-transclusion-missing |
solutions/determined/crates/determined-core/src/wire/mod.rs#AgentSkillNoteDetail | agentSkillGetNote(entry) returns the raw body and the resolved kind — everything loadNote needs |
Proposed
Section titled “Proposed”agentPantsEditorProvider implements loadNote, a real assetUrl and searchHeadings. Embeds
expand inline: the body widget renders the target’s content behind a fold toggle, indented under a
left rule, with a badge naming the included note’s kind. LoadedNote carries an optional kind
and icon so the badge is read from what the loader returned rather than looked up a second time
by the widget. The hover preview needs no work of its own — both gates read provider.loadNote,
so it lights up as a consequence.
resolveLink returns the vault-relative path rather than a route. LinkResolution.path is what
loadNote, searchHeadings and the hover preview all receive, and no Agent Manager page listens
to MdSurface’s open-link today, so nothing is relying on the route shape.
Approach
Section titled “Approach”- Settle the path shape first:
resolveLinkreturns the vault-relative path, and each page’sopen-linkhandler maps that to/apps/agent-pants/notes/<path>. Open decision inside this step: the alternative is leavingresolveLinkalone and stripping the route prefix insideloadNote. Rejected — two spellings of one path is the bug this avoids. - Implement
loadNote(path)overagentSkillGetNote(entry), returning the rawbody. Cache per path for the editor’s lifetime; the widget’s owntransclusionCachehandles redraw. - Implement
assetUrl(target, fromPath)over the note’s ownresources, so an image a bundle ships renders instead of resolving missing. - Implement
searchHeadings(notePath, q)over the loaded body, which turns on[[Note#completion across notes. LoadedNotegains optionalkindandiconinpackages/ts/obsidian-md/src/types.ts; the provider fills them fromAgentSkillNoteDetail.kindand the experience’sKIND_ICON.TransclusionBodyWidget: a fold toggle in a header row, a left rule and indent on the container, and the kind badge when the loaded note carried one. Style the new parts intheme.tsbeside the existing.cm-transclusion-*rules, and mirror them inpackages/ts/markdown-ui/app/assets/css/markdown-ui.csswhere the surface restyles the pill. Open decision in this step: whether the fold state is per widget instance or remembered per target. Per instance, matching every other CodeMirror widget.- Add the
open-linkhandler to the fouragentPantsEditorProvidercall sites — the notes page, the plugins page, the marketplace page and the wizard. - Tests: an
obsidian-editortest that a provider withloadNoteproduces a body widget and one without produces only a pill; a provider test forloadNote,assetUrlandsearchHeadings.
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
solutions/determined/experiences/agent-pants/app/composables/useAgentPantsEditorProvider.ts | modify | Implement loadNote, assetUrl and searchHeadings; resolveLink returns the vault-relative path |
solutions/determined/experiences/agent-pants/app/composables/useAgentPantsEditorProvider.test.ts | modify | Cover the three new methods and the path shape |
packages/ts/obsidian-md/src/types.ts | modify | LoadedNote gains optional kind and icon |
packages/ts/obsidian-editor/src/plugins/embeds.ts | modify | TransclusionBodyWidget gains the fold toggle, the left rule and the kind badge |
packages/ts/obsidian-editor/src/theme.ts | modify | Rules for the fold header, the rule/indent and the badge |
packages/ts/markdown-ui/app/assets/css/markdown-ui.css | modify | Mirror the new transclusion chrome in the surface’s own styling |
solutions/determined/experiences/agent-pants/app/pages/apps/agent-pants/notes/[...path].vue | modify | Handle open-link against the vault-relative path |
solutions/determined/experiences/agent-pants/app/pages/apps/agent-pants/plugins/[...path].vue | modify | Same |
solutions/determined/experiences/agent-pants/app/pages/apps/agent-pants/index.vue | modify | Same |
solutions/determined/experiences/agent-pants/app/components/ApNewComponentWizard.vue | modify | Same |
packages/ts/obsidian-editor/test/ | modify | Body widget present with loadNote, pill only without it |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1: A skill body containing
other-skillrenders that note’s content below the line in the Agent Manager editor. - AC-2: The rendered embed carries a fold toggle; collapsing it leaves the inline pill and the document text unchanged.
- AC-3: The embed’s header badge names the included note’s kind, and the kind comes from the
LoadedNotethe provider returned. - AC-4: Hovering a
wikilinkin the Agent Manager editor shows the hover-preview card, with no change toMdSurface.vueorMdHoverPreview.vue. - AC-5:
image.pngfor a file the bundle carries renders the image rather than resolving missing. - AC-6: Typing
[[other-skill#offers that note’s headings. - AC-7: An embed of a note that does not exist renders the missing pill and no body widget.
- AC-8: An unedited save of a note containing an embed leaves the file’s sha unchanged.
Out of scope
Section titled “Out of scope”- Nested transclusion past depth 1. The renderer emits nested embeds as inert placeholders and that stays.
- Editing inside an expanded embed; the body widget is read-only.
- The Related tree over the same links (T-7UDE-related-files-tab).
searchTags, which still answers empty — this experience has no tag census.- Markdown styling beyond the transclusion chrome (T-XGF1-markdown-styling-pass).
Dependencies
Section titled “Dependencies”- none
Discovery context
Section titled “Discovery context”The user’s planning request of 2026-09-07 asked for transclusions to render inline, foldable, with
the kind of what they include. Member of milestone M-BMFD.
solutions/agent-pants/docs/vault/reference/obsidian-transclusion.md and
solutions/agent-pants/docs/vault/research/obsidian-inline-rendering.md record the behaviour being
matched. The provider’s own doc comment states why assetUrl answers null today — a skill’s peer
files were listed by name and never fetched — which this task changes.
Done in #2011 (commit ec8474c2b), with the kind’s
icon glyph following in #2016 (commit b6f3bad04).
Asserted by solutions/determined/products/agent-pants/tests/e2e/transclusion.e2e.ts.