feat(core): index Markdown links to project files - #1514
Conversation
Signed-off-by: phernandez <paul@basicmachines.co>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a086cfbf87
ℹ️ 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".
Signed-off-by: phernandez <paul@basicmachines.co>
|
Codex Review: Didn't find any major issues. Keep them coming! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
… time A Markdown link was the only relation whose meaning depended on where the parser read the bytes: the parser derived the note's project path from the filesystem path with relative_to and turned the href into a rooted path at parse time. Content parsed from anywhere outside the project root raised (cloud reads a note from object storage into a temp file), and any other temporary location gave every link the wrong base. Wikilinks are recorded as authored and resolved later against database state. Path links now behave the same way: - The parser stores the path as the author wrote it: ../guides/Guide.md, ./same.md (a bare same.md gets the ./ mark so the stored target says it is a path and not a title), or a rooted /root.md. parse() takes no source path. - Both resolvers detect a path target (/, ./, ../) after wikilink normalization and resolve it against the note's own project path with resolve_project_path. Exact file only; no title, permalink, alias or cross-project fallback; a path that climbs past the root names nothing. Path-shaped wikilinks such as [[../x.md]] follow the same rule. - Background resolution keys targets by RelationTargetRequest(link_text, source_path). Identity targets carry no source and resolve once for every note; path targets are keyed by their source note, so ./Guide.md from two folders resolves to two files in one pass. Source paths are loaded with one find_by_ids call only when a batch contains a path target. - The write-time self-link check resolves the authored path against the note's own path. Existing relation rows for Markdown links are rewritten to the authored form on the note's next edit or reindex, as the docs already state. Refs #1514 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019YW9ysxugGGBCNEGzsxtFV Signed-off-by: phernandez <paul@basicmachines.co>
Why
Ordinary Markdown links currently navigate in editors but contribute no Basic Memory graph edges. This implements the latest direction in #1246: recognize links to paths inside the project, similarly to inline wikilinks, without a syntax mode or an export conversion.
Refs #1246.
What Changed
links_torelations to project files./starts at the project root. Percent-encoded filenames are decoded and fragment/query suffixes do not alter the target file.bm_parse_semantics: falseare preserved.Implementation Details
The entity parser consumes MarkdownIt's parsed link tokens and stores a normalized project-root path as the relation target. Both ordinary and bulk relation resolution treat rooted targets as exact file identities, without title, permalink, filename alias or cross-project fallback. Missing paths remain unresolved for later index passes.
No schema migration or second graph representation is needed.
docs/MARKDOWN_RELATIONS.mddocuments the behavior and its limits.Testing
uv run pytest tests/markdown tests/services/test_link_resolver.py tests/services/test_bulk_link_resolver.py tests/services/test_markdown_path_resolution.py test-int/mcp/test_markdown_path_relations_integration.py -q --no-cov: 390 passed.BASIC_MEMORY_TEST_POSTGRES=1 uv run pytest test-int/mcp/test_markdown_path_relations_integration.py tests/services/test_markdown_path_resolution.py tests/services/test_bulk_link_resolver.py -q --no-cov: 10 passed.just fast-check,just doctor, andgit diff --check: passed.Risks / Follow-ups
Existing notes gain these edges on their next edit or reindex. Rooted relation targets now mean exact project file paths, so a rooted spelling does not fall back to a similarly named title or permalink. Ordinary Markdown links are untyped
links_toedges; typed relations still use wikilinks. This change does not claim full OKF conformance or implement bundle import/export.