Open in Obsidian, Actually — Vault Detection and a Cleaner Deal Header
The 'Open in Obsidian' button was silently doing nothing. Turns out `open -a Obsidian /some/folder` is a no-op unless that folder *is* a vault — so we taught the app to walk up to the nearest `.obsidian/` and route through `obsidian://` URIs instead. While we were in there, the deal-workspace header that hosted that button got a long-overdue redesign.
Open in Obsidian, Actually — Vault Detection and a Cleaner Deal Header
Why Care?
If you're using MemoPop as a research surface, the most valuable artifact a memo run produces is the folder full of .md files — sections, source catalogs, the cross-version best-of curation. The fastest way to live in those files is Obsidian. Until today, the "Open in Obsidian" button looked like it was working and was actually doing nothing. You clicked it, the app shrugged silently, you went on with your day mildly confused.
It now opens the firm folder inside its enclosing Obsidian vault, with the file explorer focused on the right path, the way you assumed it always did. And the row of buttons that hosts that action stopped looking like four mismatched candies arranged on a tray.
What's New?
Open in Obsidianactually opens the right vault. A new Rust query walks up from any path looking for a.obsidian/directory and returns{vault_root, vault_name, rel_path}. The frontend uses that to build anobsidian://open?vault=…&file=…URI instead ofopen -a Obsidian <folder>(which Obsidian ignores for non-vault folders).Graceful Finder fallback. When the target isn't inside any Obsidian vault, the same call falls back to
revealItemInDirso the user lands in Finder rather than a confused null state.Curation reveal lands on a real note. The "Open best-of-sources/" button on the curation result banner now targets
Master-Sources.mdinside that folder — Obsidian needs a file to open, not just a directory, and the headline note is the right one.Sidecar paths come back absolute. The orchestrator's
POST /actions/curate-sourceswas returningio/alpha-partners/...becausePath('io').resolve()was missing. The Tauri side fed that relative path to/usr/bin/openwhich resolved it against the wrong cwd. One.resolve()call fixed it.Capabilities widened for
obsidian:URLs. The Tauri opener plugin rejects non-http URL schemes unless they're explicitly allowed. Addedopener:allow-open-urlwithobsidian:,https:,http:.Deal-workspace header redesigned. Single-row layout, controls all share a 32px height, the back action is a compact icon, the firm chip and version count live on one non-wrapping line, the Finder + Obsidian buttons collapsed into an icon-grouped pill with text in tooltips. The "Curate Best Sources" pill keeps its gradient prominence but no longer wraps.
The Story
We sat down to use the "Curate Best Sources" feature against the alpha-partners/ChromaDB deal. 159 sources collapsed cleanly from 392 per-section entries, the result banner appeared, we clicked the Open best-of-sources/ button — and nothing happened. No error. No window. No anything.
First instinct: the path is wrong. The error banner had been refactored to surface the exception, so we routed the open call through the wrapper that the working folder-open buttons use. That coughed up the real failure:
Couldn't open io/alpha-partners/deals/ChromaDB/exports/best-of-sources:
Launcher "/usr/bin/open"
"io/alpha-partners/deals/ChromaDB/exports/best-of-sources"
"-a" "/Applications/Obsidian.app"
failed with ExitStatus(unix_wait_status(256))There it was — a relative path. The Python sidecar was returning io/alpha-partners/... and /usr/bin/open was resolving it against its own current working directory (which isn't the orchestrator repo root). One-line fix in the FastAPI handler:
return {
...
- "output_dir": str(result.output_dir),
+ "output_dir": str(result.output_dir.resolve()),
}Restart the sidecar (the Python process needs to be re-spawned — Svelte HMR doesn't bounce it). Click again. Still nothing. No error this time, just silence.
That's when the second problem revealed itself. open -a Obsidian /some/random/folder on macOS does not surface an error and does not open the folder. Obsidian only opens vaults, not arbitrary directories. If the target isn't a vault root, the launcher exits 0 and Obsidian quietly ignores you.
The fix had to acknowledge that Obsidian is a vault-shaped app, not a folder-shaped app. So:
Walk up the directory tree from the target path looking for a
.obsidian/sibling (the marker of a vault root).If found, build the canonical deep-link URI:
obsidian://open?vault=<vault-name>&file=<rel-path-from-vault-root>. Open that as a URL via the opener plugin.If not found, fall back to
revealItemInDirso the user at least lands in Finder with the item highlighted.
The vault walker lives in Rust (apps/memopop-native/src-tauri/src/api/queries.rs) and is exposed via the same HTTP-style router pattern the rest of the local-only routes use:
pub fn find_obsidian_vault(path: &str) -> Value {
let target = Path::new(path);
let mut cursor = if target.is_file() {
target.parent().map(|p| p.to_path_buf())
} else {
Some(target.to_path_buf())
};
while let Some(dir) = cursor {
if dir.join(".obsidian").is_dir() {
// …return {vault_root, vault_name, rel_path}…
}
cursor = dir.parent().map(|p| p.to_path_buf());
}
Value::Null
}On the JS side, revealInVaultOrFinder(absPath, { preferFileInDir? }) handles both branches. The preferFileInDir option exists because the obsidian:// URI scheme has no "reveal folder" verb — for the best-of-sources case, we point Obsidian at Master-Sources.md inside the folder, which is the headline document anyway.
One last gotcha: Tauri's opener plugin rejects non-http(s) URL schemes unless the capabilities file explicitly allows them. The obsidian:// calls were getting silently dropped until we added:
{
"identifier": "opener:allow-open-url",
"allow": [
{ "url": "obsidian:" },
{ "url": "https:" },
{ "url": "http:" }
]
}With all three fixes in, the button now works end to end — across the firm-open, version-open, and best-of-sources-open call sites.
And While We Were Looking at the Header…
The deal-workspace header above the content — the row with the back button, deal title, version selector, and three action buttons — had four problems at once:
← Homerendered as a labeled button taking the visual weight of a primary action when it's really an escape hatch.The deal title was 1.4rem, the firm chip sat below it on its own line, and the version count wrapped to a third line when the firm name was long.
Curate Best Sources+Open in Finder+Open in Obsidianwere three same-styled buttons whose long labels wrapped to 2–3 lines each in normal window widths. The result looked like a cluttered candy tray.There was no shared height rhythm between the version dropdown and the buttons — different paddings, different border radii, different colors.
The redesign:
[←] ChromaDB [ChromaDB-v0.0.1-1 · 2d ago ▾] [✨ Curate Best Sources] [📁│📓]
alpha-partners · 8 versionsOne row,
justify-content: space-between, flexAll controls share
--ctl-height: 32pxand--ctl-radius: 8px← Homecollapses to a 32×32 icon button (label moved totitle/aria-label)Title drops to 1.25rem with
text-overflow: ellipsisSubtitle is a single non-wrapping line: firm chip + version count
Version select gets a custom SVG caret and a slate-rgba background that works in both light and dark
"Curate Best Sources" keeps its violet→pink gradient but gains a subtle violet glow shadow and a spinning
⏳glyph during the runFinder + Obsidian collapse into a bordered icon-group pill: two 32×32 icon buttons sharing one border, divider between them, text moved to tooltips. The Obsidian icon gets a subtle violet hover tint to hint at its role
All the old hardcoded light/dark CSS for these controls was replaced with
rgba(slate)tokens that work in both modes without separate@mediablocks
The dead .notebook-btn and .finder-btn styles were swept out. The result reads as one rhythm, no labels wrap, and the row stops competing with the actual content below it.
How to Test
Quit MemoPop (
Cmd-Q) and relaunch — the Rust crate changed, so HMR isn't enough.Open a deal that has at least one prior memo run (e.g.
alpha-partners / ChromaDB).Confirm the header: single row, no wrapped labels, the back arrow is now icon-only.
Click Curate Best Sources. Wait for the violet banner.
Click Open best-of-sources/ on the banner — Obsidian should focus the
alpha-partnersvault and openMaster-Sources.md.Click the 📓 icon in the header group — Obsidian should focus the same vault at the firm root.
Click the 📁 icon — Finder reveals the current version's folder.
(Optional) Point at a path that's not inside an Obsidian vault — both icon buttons should now fall through to Finder rather than silently doing nothing.
What's Next
The Trustworthy Citations rollout (
Trustworthy-Citations-Source-Harvester-Rollout.mdin the orchestrator'scontext-v/plans/) is the next push. Phase 1 — fix the self-disabling URL validator atcitation_validator.py:302, swap the HEAD-only urllib probe for a real GET, add the verdict ladder (verified-accessible/verified-gated/verified-via-republish/soft-404-graceful/hard-404/hallucinated-pattern/thin/title-swapped) plus a reputable-gated publisher allow-list. Today's curation banner deliberately admits "Validity not yet checked — soft-404s and paywall stubs may still be present"; that caveat goes away once Phase 1 lands.The Obsidian-not-installed case currently surfaces the macOS handler-missing dialog if you click 📓 without Obsidian. A graceful frontend fallback to Finder when
openUrl('obsidian://…')rejects would be friendlier.The vault walker is wired only into the three deal-workspace open buttons today. If we add more reveal actions elsewhere (job view, outline tree, brand config viewer), they should route through the same
revealInVaultOrFinderhelper.
