Domain: Roadmaps — Function Reference

Manages educational roadmaps sourced from roadmap.sh. Each roadmap is a directory at data/roadmaps/{id}/ containing {id}.md (frontmatter + markdown), {id}.json (visual graph of nodes/edges), and content/ subdirectory of topic files named {label}@{nodeId}.md. Progress is stored in SQLite. Five in-memory LRU caches with file-signature invalidation.

MCP Tools Exposed

Tools exposed through unified controller. Key names: roadmap_list, roadmap_get, roadmap_nodes, roadmap_node, roadmap_register, roadmap_validate, roadmap_validate_all, roadmap_repair, roadmap_repair_all, roadmap_parse_yaml, roadmap_progress, roadmap_update_progress, roadmap_update_progress_batch, roadmap_check_prerequisites, roadmap_next_topic, roadmap_analyze_structure, roadmap_export_to_gsd.

Tool Name Description Key Inputs Returns
roadmap_list List all available roadmaps none { success, count, roadmaps[] }
roadmap_get Get roadmap markdown content roadmapId: string { success, roadmap: { id, title, description, metadata, content, path } }
roadmap_register Register a custom roadmap roadmapId, title?, description?, markdown?, graph?, overwrite? { success, message, roadmap }
roadmap_nodes Get merged graph+content nodes roadmapId: string Full node list with dependencies, resources, content
roadmap_node Get a specific node with full content roadmapId, nodeId { success, node }
roadmap_validate Validate graph+content integrity roadmapId: string { success, status, score, issues, graph, content }
roadmap_validate_all Validate all or selected roadmaps roadmap_ids?, include_passing?, max_results? Aggregated quality report
roadmap_repair Repair roadmap data issues roadmapId, dry_run?, fix_graph?, fix_content?, create_missing_content?, remove_self_loops? { success, dryRun, changes, actions[], validation }
roadmap_repair_all Batch repair roadmaps Same as repair + confirm_apply_all?, only_statuses? Batch repair summary
roadmap_progress Get node progress for roadmap roadmapId: string { success, roadmapId, progress: { [nodeId]: status } }
roadmap_update_progress Update single node status roadmapId, nodeId, status { success, message, roadmapId, nodeId, status }
roadmap_update_progress_batch Update multiple node statuses roadmapId, updates[]: [{ node_id, status }] { success, roadmapId, updated, failed, results[], errors[] }
roadmap_check_prerequisites Check node prerequisites met roadmapId, nodeId { prerequisites: { total, completed, inFlight, notStarted, missing[], satisfied, statusByNode } }
roadmap_next_topic AI-scored next topic recommendation roadmapId, currentNodeId? { nextTopic, recommendation, alternatives[] }
roadmap_analyze_structure Structural stats and critical path roadmapId, depth? { stats, criticalPath[], topTopics[] }
roadmap_export_to_gsd Export roadmap to GSD project roadmapId, projectName, pace? { success, projectPath, topicCount, totalNodes, pace, validation }

Core Functions

getRoadmapDir(roadmapId)

Purpose: Return absolute path to roadmap folder. Parameters: roadmapId: string Returns: string path. Validates ID against ROADMAP_SAFE_ID_PATTERN.

getRoadmapPath(roadmapId)

Purpose: Return path to {id}/{id}.md. Returns: string

getRoadmapJsonPath(roadmapId)

Purpose: Return path to {id}/{id}.json. Returns: string

registerRoadmap(roadmapId, options)

Purpose: Create a new custom roadmap directory with markdown and graph files atomically (temp dir → rename). Parameters: roadmapId: string, options: { title?, description?, markdown?, graph?, overwrite? } Returns: { success, message, roadmap: { id, title, description, path, graphPath, contentDir } } Side effects: Creates directory at ROADMAPS_DIR/{id}/, writes .md and .json, invalidates caches. Notes for rewrite: Graph integrity is validated before write (no invalid IDs, no invalid edges, no duplicate node IDs).

listRoadmaps()

Purpose: Scan ROADMAPS_DIR for subdirectories with matching .md files. Returns: { success, count, roadmaps[] } sorted by title.

getRoadmap(roadmapId)

Purpose: Read and parse roadmap markdown with LRU cache keyed on file mtime+size. Returns: { success, roadmap: { id, title, description, metadata, content, path } }

getRoadmapNodes(roadmapId)

Purpose: Merge JSON graph nodes with content map; build dependency/dependent adjacency lists. Returns: { success, roadmapId, totalNodes, topicCount, subtopicCount, todoCount, checklistCount, withContent, totalResources, nodes[], edges[], connections[], validationWarnings } Notes for rewrite: Filters to MEANINGFUL_NODE_TYPES = {topic, subtopic, todo, checklist}. Each node gets dependencies[] and dependents[] from edge traversal.

getRoadmapNode(roadmapId, nodeId)

Purpose: Fetch a single node with full raw content. Returns: { success, node: { ...node, fullContent } }

validateRoadmap(roadmapId)

Purpose: Integrity check: graph anomalies (orphan edges, self-loops, duplicates, invalid IDs) + content mapping (unmatched files, missing node content). Returns: { success, roadmapId, status: 'pass'|'warn'|'fail', score, summary, issues, graph, content } Algorithm: score = 100 - (errors × 25) - (warnings × 5), clamped to 0.

validateAllRoadmaps(options)

Purpose: Batch validate all or selected roadmaps; aggregates pass/warn/fail counts. Parameters: options: { roadmap_ids?, include_passing?, max_results? } Returns: Aggregated report with sorted results (fail < warn < pass, then by ascending score).

repairRoadmap(roadmapId, options)

Purpose: Fix detected issues: remove invalid/duplicate nodes+edges, move invalid/duplicate/unmapped content files, create placeholder content for missing nodes. Parameters: roadmapId, dry_run? (default true), fix_graph?, fix_content?, create_missing_content?, remove_self_loops? Returns: { success, dryRun, applied, fixesAttempted, changes, actions[], validation } Notes for rewrite: Default is dry_run=true — safe to call for audit. Write only when dry_run=false.

repairAllRoadmaps(options)

Purpose: Batch repair. Requires confirm_apply_all=true for non-dry-run global scope. Returns: Batch summary with before/after status per roadmap.

parseRoadmapYaml(roadmapId)

Purpose: Extract and parse YAML frontmatter (or fenced code block) from roadmap markdown. Returns: { success, data } or error.

getProgress(roadmapId)

Purpose: Retrieve all node progress statuses from SQLite. Returns: Promise<{ success, roadmapId, progress: { [nodeId]: status } }>

updateNodeProgress(roadmapId, nodeId, status)

Purpose: Set a single node’s progress status. Returns: Promise<{ success, message, roadmapId, nodeId, status }>

updateProgressBatch(roadmapId, updates)

Purpose: Update multiple node progress statuses. Parameters: roadmapId: string, updates: [{ node_id, status }] Returns: Promise<{ success, roadmapId, updated, failed, results[], errors[] }>

checkPrerequisites(roadmapId, nodeId)

Purpose: Check if all graph dependencies of a node are completed/mastered. Parameters: roadmapId, nodeId Returns: Promise<{ prerequisites: { total, completed, inFlight, notStarted, missing[], satisfied, statusByNode } }>

getNextTopic(roadmapId, currentNodeId)

Purpose: AI-scored recommendation for the next topic to study. Returns: Promise<{ success, nextTopic, recommendation: { reason, score, prerequisites[], unlocks[] }, alternatives[] }> Notes for rewrite: See scoring algorithm below.

analyzeRoadmapStructure(roadmapId, depth)

Purpose: Stats on node types, edge complexity, resource counts, and topological levels. Parameters: roadmapId, depth?: number (default 2) Returns: { stats, criticalPath[], topTopics[] }

exportToGSD(roadmapId, projectName, pace)

Purpose: Export roadmap to a GSD project directory with TODOS.md and PLAN.md; creates/upserts GSD project in DB. Parameters: roadmapId, projectName, pace: fast|normal|deep Returns: Promise<{ success, message, projectPath, topicCount, totalNodes, pace, validation }>

initRoadmapDomain()

Purpose: Log roadmap count on startup.

Database Operations

Operation Query Pattern Tables Used
Get progress SELECT all progress for roadmap roadmap_progress
Update progress UPSERT node status roadmap_progress
Create GSD project INSERT or REPLACE gsd_projects
Get GSD project by name SELECT by name gsd_projects

All roadmap data (graph, content, metadata) is read from the filesystem, not SQLite.

Key Algorithms

LRU Cache with File Signature Invalidation

signature = mtime_ms + ":" + file_size
getCachedValue(cache, key, signature):
  entry = cache.get(key)
  if not entry or entry.signature != signature: return null
  // LRU: move to end (delete + re-insert)
  cache.delete(key); cache.set(key, entry)
  return entry.value

setCachedValue(cache, key, signature, value, maxSize):
  cache.delete(key) if exists; cache.set(key, { signature, value })
  while cache.size > maxSize: delete oldest key

Five caches: metadata, document, graph, content, nodes. Each keyed by roadmapId.

Content File Parsing (loadContentFiles)

filename pattern: {label}@{nodeId}.md
for each file matching pattern:
  extract resources via regex: - [@{type}@{title}]({url})
  also extract standard markdown links
  extract description: first non-heading paragraphs before resource list
  store in contentMap: nodeId → { name, file, description, resources, rawContent }

Graph Integrity Analysis (analyzeGraphIntegrity)

nodeIds = Set of valid node IDs (no blank ID, de-duplicated)
for each edge:
  skip if source/target blank (invalidEdgeCount++)
  skip if filter excludes nodes
  if source or target not in nodeIds: orphanEdges.push(...)
  if source == target: selfLoopEdges.push(...)
  if edgeKey already seen: duplicateEdges.push(...)

Next Topic Scoring (getNextTopic)

available = nodes where status != completed/mastered AND all prerequisites satisfied
for each available node:
  score = directDependents * 10
         + transitiveDependents(depth=3) * 5
         + (type == "topic" ? 15 : 0)
         + (hasContent ? 5 : 0)
         + resources.length * 2
sort descending; return top + alternatives[1..3]

Topological Level Grouping (groupByLevel)

assigned = Set()
while assigned.size < nodes.length:
  level = nodes where not assigned AND all dependencies assigned
  if level is empty: break (cycle detected)
  add all to assigned
  push level IDs to levels[]
return levels

Graph Repair (repairRoadmap)

Nodes: deduplicate (keep first), drop blank IDs
Edges: drop blank source/target, drop orphan edges (nodes not in valid set),
       drop self-loops (if removeSelfLoops), deduplicate
Content: move invalid-format files → _invalid/
         move duplicate-nodeId files → _duplicates/
         move files mapping to non-meaningful nodes → _unmapped/
         create placeholder files for meaningful nodes with no content (if createMissingContent)

Back to top

Colibri — documentation-first MCP runtime. Apache 2.0 + Commons Clause.

This site uses Just the Docs, a documentation theme for Jekyll.