Datacore Query Directions¶
How to translate user intent into Datacore vault queries — schema-first, decomposition, plan vs raw query, validate-and-repair
When to use¶
user wants to search the vault structurally using Datacore (pages, tasks, sections, blocks, containment, tags, frontmatter)
Slash command: /wb-datacore-query
Related capabilities¶
context/datacore_schemacontext/datacore_run_plancontext/datacore_querycontext/datacore_fullquerycontext/datacore_validatecontext/datacore_get_pagecontext/datacore_evaluatecontext/datacore_compile_plan
Directions¶
Query the Obsidian vault structurally using Datacore.
Step 1: Discover the schema (mandatory)¶
Always fetch the vault schema first:
mcp__work-buddy__wb_run("datacore_schema")
This returns object type counts, top tags, frontmatter keys, and path prefixes. Do not skip this -- guessing at tag names or paths is the #1 cause of empty results.
Step 2: Decompose the request¶
- Identify the target object type (pages, tasks, sections, blocks)
- Map the user's language to Datacore primitives using the schema
- Identify containment relationships (childof, parentof)
- Check for ambiguity -- surface both interpretations and ask before executing
Step 3: Build and execute¶
Preferred: use datacore_run_plan with a structured plan JSON. Direct: use datacore_query with raw Datacore syntax.
Plan keys: target, path, tags, tags_any, status, text_contains, frontmatter, child_of, parent, exists, expressions, negate.
Step 4: Validate and repair¶
- Error: fix syntax, retry once
- Zero results: check tag names against schema, relax one condition, retry. State what changed.
-
200 results: suggest tightening
- Results look right: proceed to presentation
Do at most one repair attempt.
Step 5: Present results¶
- Show the compiled query
- Format as concise table/list appropriate to object type
- Highlight anything surprising
Object types and fields¶
@page: $path, $frontmatter, $tags, $links, $ctime, $mtime, $size, $sections @task: $text, $status, $file, $tags, $parentLine, $symbol @section: $title, $level, $ordinal, $tags @block: $type, $ordinal, $tags, $infields @list-item: $text, $symbol, $tags, $file @codeblock: $type, $ordinal
Serialization¶
Datacore result objects have circular parent/child references. The JS snippets handle this: - Page objects: Use page.json() which produces clean JSON. Sections flattened to summaries. - Non-page objects (tasks, list-items, blocks): Manual serialization — primitive fields kept, arrays truncated, objects stringified. - Timestamps: $ctime/$mtime come as epoch ms from json() or Luxon DateTime strings from value().
Known gotchas¶
- path() works on @page only, not @task -- use $file for tasks
- Timestamps are Luxon DateTimes -- use date("YYYY-MM-DD") for comparisons
- Result objects have circular references -- sections are flattened to summaries
- Bridge latency: Each call goes through HTTP bridge (~5s round-trip). Not suitable for high-frequency polling.
- Schema sampling: datacore_schema stride-samples pages. May miss rare tags/frontmatter.
- tryQuery/tryFullQuery: The Result wrapper uses {value, successful} not {ok}.
- fields() method: Not available on query result objects. Use value('$fieldname') instead.
- Large result sets: Always use limit parameter. The full vault has 200k+ blocks.
Don'ts¶
- Don't skip schema discovery
- Don't import work_buddy.* modules -- use MCP capabilities
- Don't dump raw JSON -- format results for readability
- Don't run queries without field selection on large result sets
- Don't silently pick one interpretation when ambiguous -- ask
- Don't retry more than once on failure