[#13] Optional: render topics as Obsidian #hashtags#27
Merged
Conversation
Add `[output] topic_style = "wikilink" | "hashtag"` config flag (default `wikilink`, backwards-compatible). When set to `hashtag`, the in-body `**Topics:**` line is emitted as `#ai-coding #software-engineering` instead of `[[ai-coding]] · [[software-engineering]]` — so the line is a tappable Obsidian tag in addition to the frontmatter `tags:` entries. Scope is the in-body line only. Frontmatter `tags:`, `_index.md`'s `## Topics` ranking and topic-page post lists keep wikilinks — those are navigational by design. The flag is validated at config-load time and re-validated at the `generate()` boundary so programmatic callers (tests, notebooks) fail fast on a typo. PRD: docs/prds/2026-05-22-xbrain-13-hashtag-topics.md (in vault) Plan: docs/implementation-plans/2026-05-22-xbrain-13-hashtag-topics.md Tests: - 4 new in test_generate.py: wikilink default, hashtag mode, hashtag mode does not bleed into the index, unknown style raises. - 3 new in test_config.py: defaults to wikilink, hashtag round-trips, unknown style rejected. Quality gate: all critical checks pass · 306 tests · 88% coverage.
This was referenced May 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #13.
Summary
Adds an opt-in config flag,
[output] topic_style = "wikilink" | "hashtag", sothe in-body
**Topics:**line on each item note can be rendered as Obsidianhashtags instead of wikilinks. Default is
wikilink— fullybackwards-compatible.
wikilink(default):**Topics:** [[ai-coding]] · [[software-engineering]]hashtag:**Topics:** #ai-coding #software-engineeringFrontmatter
tags:, the_index.md## Topicsranking and the topic-pagepost lists are unchanged — those are navigational by design and stay
wikilinks regardless of
topic_style.Decisions (resolved in the PRD)
note exists (every topic page is
topics/<slug>.md); "alongside" doubledthe line noise without paying for itself.
[output] topic_style— sits next to the existing[output] language. Backwards-compatible default"wikilink".^[a-z0-9]+(?:-[a-z0-9]+)*$,per
models.py:Topic.slug) are a strict subset of Obsidian's tagcharset
[A-Za-z0-9/_-], so no slug change is needed.asserted in
test_generate_renders_topics_as_hashtags_when_requested).Implementation
Config.topic_style: str(src/xbrain/config.py) — read from[output].topic_style, defaults to"wikilink", validated againstSUPPORTED_TOPIC_STYLES = ("wikilink", "hashtag"). Unknown value →clean
ValueErrorlisting the supported set.generate(..., topic_style: str = "wikilink")— threads the valuethrough to
_enrichment_lines. DefensiveValueErrorat the entrypoint for programmatic callers (mirrors how
output_languageisvalidated by
strings_for()on entry).cli.py:_run_generatepassescfg.topic_stylethrough.config.toml.exampleand the README config table + TOML block documentthe new key. README Layer 1 gets a one-sentence note pointing to the
hashtag mode near the existing example.
topic_styleis a layout choice, not a locale concern,so it stays on
Configrather than enteringxbrain.i18n.Tests
7 new tests, all green:
tests/test_generate.pytest_generate_renders_topics_as_wikilinks_by_default— default modekeeps the exact current line.
test_generate_renders_topics_as_hashtags_when_requested— sameitem, hashtag mode, asserts the body line + frontmatter unchanged.
test_generate_hashtag_mode_does_not_affect_index_or_topic_page_lists— the
## Topicsranking still uses wikilinks.test_generate_rejects_unknown_topic_style—ValueErrorlistingsupported values.
tests/test_config.pytest_load_config_defaults_topic_style_to_wikilinktest_load_config_round_trips_hashtag_topic_styletest_load_config_rejects_unknown_topic_styleQuality gate (
uv run poe check)Out of scope
--topic-stylefor one-off overrides (file a follow-up issue ifneeded).
wikilinktohashtag.