| name | debugging |
| description | Debug issues in the Second Brain Nuxt 4 + @nuxt/content v3 project. Use for any bug, test failure, or unexpected behavior. |
Second Brain Debugging
Overview
This skill adapts systematic debugging for the Second Brain stack:
- Nuxt 4 with Vue 3 Composition API
- @nuxt/content v3 with SQLite and minimark format
- @nuxt/ui v4 components
- D3.js for knowledge graph visualization
Core principle: ALWAYS trace data flow before attempting fixes.
Stack-Specific Gotchas
Before debugging, internalize these common pitfalls:
| Issue | Symptom | Cause |
|---|
| Empty graph edges | Nodes show, no connections | Missing .select('body') in query |
| Links not extracted | Backlinks/graph empty | Minimark parsed as object, not array |
| 404 on content page | Page not found | Slug mismatch (/slug vs slug) |
| Stale backlinks | Old connections shown | useAsyncData cache not invalidated |
| Silent API failure | Empty response, no error | try-catch returns {} or [] |
| Wrong mentions | Unrelated content matched | Title regex too broad |
| Graph crashes on filter | D3 error after filtering | Edge source/target type mismatch |
The Four Phases
Phase 1: Identify the Layer
Data flows through these layers:
Content File (Markdown)
↓ Parsed by Nuxt Content
Minimark AST (body.value array)
↓ Queried via queryCollection
API Endpoint (server/api/*.ts)
↓ Returned as JSON
Vue Composable (useBacklinks, useMentions)
↓ Rendered in component
User Interface
First question: Which layer is broken?
- Content layer - Check frontmatter, markdown syntax
- AST layer - Check minimark structure:
[tag, props, ...children]
- Query layer - Check
.select('body'), path matching
- API layer - Check response structure, error handling
- Client layer - Check composable logic, reactivity
Quick diagnostic:
pnpm nuxi dev
Phase 2: Trace Data Flow
For content/link issues:
-
Check raw content file:
- Frontmatter has
title and type?
- Wiki-links use correct format
[[slug]]?
- File in
/content/ directory?
-
Check minimark extraction:
console.log("Body structure:", JSON.stringify(item.body, null, 2));
-
Check query selection:
queryCollection(event, "content")
.select("path", "stem", "title", "type", "body")
.all();
-
Check API response:
curl http://localhost:3000/api/graph | jq '.edges | length'
curl http://localhost:3000/api/backlinks | jq 'keys | length'
For graph visualization issues:
- Check nodes exist before filtering
- Check edge source/target types (string vs object after D3)
- Check filter state in URL query params
Phase 3: Hypothesis Testing
Form ONE hypothesis:
- "The body isn't being selected because..."
- "Links aren't extracted because minimark format is..."
- "The cache is stale because..."
Test minimally:
vp test --project unit -- minimark
vp test -- graph
Add targeted logging:
console.log("Body type:", body?.type);
console.log("Body value is array?", Array.isArray(body?.value));
console.log("First node:", JSON.stringify(body?.value?.[0]));
Phase 4: Fix and Verify
-
Create failing test first:
it("extracts links from nested minimark", () => {
const body = {
type: "minimark",
value: [["a", { href: "/target" }, "Link text"]],
};
expect(extractLinksFromBody(body)).toContain("target");
});
-
Implement fix in ONE place
-
Verify with full test suite:
vp test
vp check && pnpm typecheck
-
If fix doesn't work after 3 attempts:
- Question the architecture
- Is the data model fundamentally sound?
- Should slug normalization be centralized?
Quick Debugging Commands
vp test
vp test --project unit -- minimark
vp test -- graph.nuxt
pnpm typecheck
pnpm dev
curl -s http://localhost:3000/api/graph | jq '.nodes | length'
curl -s http://localhost:3000/api/graph | jq '.edges | length'
curl -s http://localhost:3000/api/backlinks | jq 'keys'
curl -s "http://localhost:3000/api/mentions?slug=test&title=Test" | jq
Key Files by Subsystem
Content Pipeline
/content/*.md - Raw content files
/content.config.ts - Collection schema (title, type required)
/modules/wikilinks.ts - [[link]] to anchor transformation
Link Extraction
/server/utils/minimark.ts - Extract links from AST
- Body format:
{ type: 'minimark', value: [...arrays...] }
- Link format:
['a', { href: '/slug' }, 'text']
API Endpoints
/server/api/graph.get.ts - Nodes and edges for D3
/server/api/backlinks.get.ts - Reverse link index
/server/api/mentions.get.ts - Unlinked mentions search
Client Composables
/app/composables/useBacklinks.ts - Fetch backlinks
/app/composables/useMentions.ts - Fetch mentions
/app/composables/useGraphFilters.ts - Graph filter state
Pages
/app/pages/[...slug].vue - Content page
/app/pages/graph.vue - Knowledge graph
Common Fixes
"Graph shows nodes but no edges"
queryCollection(event, "content")
.select("path", "stem", "title", "type", "tags", "body")
.all();
"Links not being extracted"
function extractLinksFromMinimark(node: unknown): string[] {
if (!Array.isArray(node)) return [];
const [tag, props, ...children] = node;
}
"Stale backlinks after content edit"
const { data: backlinks, refresh } = await useAsyncData(
`backlinks-${Date.now()}`,
() => $fetch("/api/backlinks"),
);
"Content page 404"
const slug = route.path.startsWith("/") ? route.path : `/${route.path}`;
Red Flags - STOP
If you catch yourself:
- Guessing which layer the bug is in
- Adding fixes to multiple files at once
- Skipping the test before fixing
- Not checking minimark format
- Assuming body is included by default
STOP. Return to Phase 1.