Document Portal & Obsidian: Integration Analysis
Analysis of how Obsidian.md and the document portal work together as a content pipeline, with observations, trade-offs, and potential improvements.
How they fit together
The vault root is /home/ajb/Work/website — the same directory as the web application. Every .md file in docs/ is both an Obsidian note and a portal page. The workflow:
- Edit/create
.mdfiles in Obsidian (preview mode) - The portal's routes (
/docs,/docs/{slug}) serve them dynamically with hot-reload - Tags (
#tagname) are extracted at render time by the portal and used for search/filtering - Cross-links use
.mdextension syntax and are rewritten server-side to portal URLs
No build step, no duplication, no sync — the file system is the single source of truth.
Pros
1. Instant feedback loop
Obsidian saves on every keystroke; uvicorn --reload picks up file changes immediately. Refresh the browser to see edits live. No build pipeline, no watcher configuration.
2. Tag consistency
Both systems use inline #tag syntax:
- Obsidian shows tags in its tag pane and graph view
- The portal extracts them for search, autocomplete, and filtering
- Same source, same tags, no duplication
3. Cross-links in both directions
Obsidian's graph view and backlinks panel show relationships between docs. The portal's DocLinkExtension rewrites .md links to portal URLs, so clicking a link in a portal page navigates correctly. Links authored in Obsidian as [text](file.md) work in both contexts.
4. No frontmatter required
The portal works with raw markdown — no YAML frontmatter needed. This keeps files lightweight and compatible with any markdown editor, not just Obsidian.
5. File structure is the URL structure
The file tree in Obsidian's file explorer mirrors the portal's URL hierarchy. docs/about_me.md → /docs/about_me. What you see in the sidebar is what you get in the browser.
6. Git-friendly
.md files are plain text, tracked in git. The .obsidian/ directory is gitignored (correctly), so the content is portable but editor-specific config stays local.
7. Live preview
Obsidian's preview mode renders headings, links, tables, and code blocks with a dark theme that approximates the portal's Bootswatch darkly theme. The editing experience visually aligns with the output.
8. No lock-in
If Obsidian were removed, the portal continues working — it just reads .md files from disk. Any editor (VS Code, vim, Typora) works identically.
Cons & Friction Points
1. Wikilink syntax mismatch
Obsidian defaults to [[wikilinks]] for internal links. The portal only processes standard markdown links ending in .md. This means:
- [[ui_themes]] renders as plain text [[ui_themes]] in the portal
- Users must manually type [UI Themes](ui_themes.md) for cross-links to work on the web
Obsidian does support markdown links natively, but muscle memory leans toward wikilinks. The portal could add wikilink support, or Obsidian could be configured (app.json → "useMarkdownLinks": true) to default to markdown links.
2. Tag extraction mismatch
Obsidian's tag pane picks up #tag anywhere in the file, including inside code blocks. The portal explicitly strips code blocks before extraction. A tag written inside a fenced code block will show up in Obsidian's tag pane but won't appear in the portal's search. This is actually correct behaviour for the portal (those tags are usually documentation examples), but the inconsistency may cause confusion when Obsidian reports a tag count that doesn't match the portal.
3. No frontmatter support in the portal
Obsidian's Properties panel stores metadata as YAML frontmatter (tags:, aliases:, created:, etc.). The portal ignores frontmatter entirely. This means:
- tags in frontmatter are not picked up by the portal's tag extraction (only inline #tag works)
- aliases are not used for URL routing or display
- created/modified dates are not surfaced in the UI
- Obsidian Sync relies on frontmatter for some features
If frontmatter tags were indexed, users could use either tags: in properties or inline #tag interchangeably.
4. No Obsidian graph in the portal
The portal has no visual graph view. Obsidian's graph shows how docs interconnect, but that insight doesn't surface on the web. A tag-based graph or a "related docs" section on each page could bridge this gap.
5. Template friction
Obsidian's Templates plugin is enabled but with no custom templates. Creating a new doc requires manually typing the #tag and # Heading boilerplate. Without a template, new docs may lack tags and won't appear in tag-based search or the home page random badges.
6. No visual preview of portal rendering in Obsidian
Obsidian's preview mode uses its own markdown renderer, not Python-Markdown with the portal's extensions. What you see in Obsidian isn't exactly what the portal produces — table styling, code highlighting theme, ToC layout, and heading anchor IDs are all portal-only features.
Possible improvements
1. Wikilink support in the portal
Add a markdown preprocessor that converts [[page]] and [[page|display text]] to standard markdown links before passing to Python-Markdown. This would make Obsidian's default link syntax work seamlessly with the portal.
WIKILINK_RE = re.compile(r'\[\[([^|]+)(?:\|([^]]+))?\]\]')
def convert_wikilinks(text: str) -> str:
return WIKILINK_RE.sub(r'[\2](\1.md)' if r'\2' else r'[\1](\1.md)', text)
This is low effort and removes the biggest integration friction.
2. Frontmatter tag extraction
Add a pass that reads YAML frontmatter and merges tags: entries with inline #tag findings. This would let users manage tags via Obsidian's Properties panel and have them appear in the portal's search.
def extract_frontmatter_tags(content: str) -> list[str]:
m = re.match(r'^---\s*\n(.*?)\n---', content, re.DOTALL)
if not m:
return []
try:
import yaml
data = yaml.safe_load(m.group(1))
return data.get('tags', []) if isinstance(data, dict) else []
except Exception:
return []
Requires PyYAML dependency but opens up Obsidian Properties integration.
3. Create an Obsidian template for new docs
Configure the Templates plugin with a template at templates/new_doc.md:
#{{title | slugify}}
# {{title}}
This ensures every new doc has a tag line and a heading, making it immediately discoverable in the portal.
Set the template folder location in app.json:
{
"templateFolder": "templates"
}
4. Obsidian markdown link mode
Set "useMarkdownLinks": true in .obsidian/app.json to make Obsidian default to [text](file.md) links instead of [[wikilinks]]. This aligns Obsidian's link insertion behaviour with what the portal supports, without any code changes.
5. Portal-side "related docs" section
On each doc page, use the tag index to surface related docs sharing the same tags. This mirrors Obsidian's backlinks/outgoing-links panel on the web.
6. Tag-graph or tag-cloud visualisation
Add a visual element to the /docs page showing tag relationships — which tags co-occur in the same docs. This brings a lightweight version of Obsidian's graph view to the portal.
7. Consistent CSS between Obsidian and portal
Create an Obsidian CSS snippet that styles preview mode to more closely match the portal's rendered output (heading sizes, link colours, code block treatment). Or reverse: extract the portal's CSS variables into a format Obsidian can consume.
8. Frontmatter-driven display titles
If frontmatter is supported, title: in frontmatter could override the first # Heading as the display title. This would let users have a different Obsidian note title than what appears in the portal's doc list and breadcrumb.
Summary
| Area | Status | Recommendation |
|---|---|---|
| Cross-links | Wikilinks broken, .md links work |
Support wikilinks in portal OR enable markdown links in Obsidian |
| Tag consistency | Tags extracted from inline only | Add frontmatter tag extraction |
| New doc creation | Manual boilerplate | Create Obsidian template |
| Visual consistency | Different renderers | CSS snippet to align preview |
| Graph/relationships | Obsidian-only | Add "related docs" to portal |
| Properties/frontmatter | Ignored by portal | Optional: YAML frontmatter support for tags and title |