
Installer
- 6 installs
- 2 repo stars
- Updated August 1, 2026
- vishalsachdev/claude-skills
Helps with ai & agent building tasks.
About
installer is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- installer
- AI & Agent Building
- AI-coding skill
Installer by the numbers
- 6 all-time installs (skills.sh)
- +1 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #12,739 of 16,556 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/vishalsachdev/claude-skills --skill installerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 6 |
|---|---|
| repo stars | ★ 2 |
| Last updated | August 1, 2026 |
| Repository | vishalsachdev/claude-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Installer
Overview
This meta-skill handles installation and setup tasks for intelligent textbook projects. It consolidates three installation skills into a single entry point with on-demand loading of specific installation guides.
When to Use This Skill
Use this skill when users request:
- Setting up a new MkDocs Material project
- Creating a new intelligent textbook from scratch
- Installing a learning graph viewer
- Setting up skill usage tracking with hooks
- Bootstrapping project infrastructure
Step 1: Identify Installation Type
Match the user's request to the appropriate installation guide:
Routing Table
| Trigger Keywords | Guide File | Purpose |
|---|---|---|
| new project, mkdocs, textbook, bootstrap, setup, template, new book | references/mkdocs-template.md | Create new MkDocs Material project |
| graph viewer, learning graph, visualization, interactive graph, concept viewer | references/learning-graph-viewer.md | Add learning graph viewer to existing project |
| track skills, skill usage, activity tracking, hooks, usage analytics | references/skill-tracker.md | Set up skill tracking with hooks |
| cover image, home page, social media, og:image, montage, book cover, index page | references/home-page-template.md | Create home page with cover image and social metadata |
Decision Tree
Creating a new project/textbook from scratch?
→ YES: mkdocs-template.md
Adding a learning graph viewer to existing project?
→ YES: learning-graph-viewer.md
Setting up skill usage tracking?
→ YES: skill-tracker.md
Creating a cover image or setting up home page with social metadata?
→ YES: home-page-template.mdStep 2: Load the Matched Guide
Read the corresponding guide file from references/ and follow its installation workflow.
Step 3: Execute Installation
Each guide contains: 1. Prerequisites and requirements 2. Step-by-step installation commands 3. Configuration options 4. Verification steps 5. Troubleshooting tips
Available Installation Guides
mkdocs-template.md
Purpose: Bootstrap a complete MkDocs Material intelligent textbook project
Creates:
- Conda virtual environment named 'mkdocs'
- Full MkDocs Material project structure
- Custom CSS for branding
- Social media card plugins
- GitHub Pages deployment configuration
Prerequisites:
- Conda installed
- Git installed
- GitHub repository created
learning-graph-viewer.md
Purpose: Add interactive learning graph exploration to existing textbook
Creates:
- Interactive vis-network graph viewer
- Search, filtering, and statistics features
- Integration with existing learning-graph.json
Prerequisites:
- Existing MkDocs project
- learning-graph.json file present
skill-tracker.md
Purpose: Set up Claude Code skill usage tracking
Creates:
- Hook scripts for tracking skill invocations
- Activity log directory structure
- Reporting scripts for usage analysis
Prerequisites:
- Claude Code installed
- ~/.claude directory exists
home-page-template.md
Purpose: Create professional home page with cover image and social media optimization
Creates:
- docs/index.md with proper frontmatter metadata
- AI image generation prompts for cover with montage background
- Open Graph and Twitter Card configuration
Features:
- Cover image design guidance (1.91:1 aspect ratio)
- Montage element suggestions by topic
- Social media preview optimization
- Example prompts for various book themes
Prerequisites:
- Existing MkDocs project
- Access to AI image generator (DALL-E, Midjourney, etc.)
Examples
Example 1: New Textbook Project
User: "I want to create a new intelligent textbook about machine learning" Routing: Keywords "create", "new", "textbook" → references/mkdocs-template.md Action: Read mkdocs-template.md and follow its workflow
Example 2: Add Graph Viewer
User: "Add an interactive viewer for the learning graph" Routing: Keywords "viewer", "learning graph", "interactive" → references/learning-graph-viewer.md Action: Read learning-graph-viewer.md and follow its workflow
Example 3: Track Skill Usage
User: "I want to track which skills I use most often" Routing: Keywords "track", "skills", "usage" → references/skill-tracker.md Action: Read skill-tracker.md and follow its workflow
Example 4: Create Cover Image
User: "Help me create a cover image for my textbook" Routing: Keywords "cover image", "textbook" → references/home-page-template.md Action: Read home-page-template.md and follow its workflow
Example 5: Set Up Home Page with Social Sharing
User: "I need to add og:image metadata to my home page" Routing: Keywords "og:image", "home page" → references/home-page-template.md Action: Read home-page-template.md and follow its workflow
Common Workflows
Full Project Setup
For a complete new project, users typically run these installations in order: 1. mkdocs-template.md - Create the project structure 2. home-page-template.md - Create cover image and configure home page 3. learning-graph-viewer.md - Add graph visualization (after learning graph exists) 4. skill-tracker.md - Enable usage analytics (optional)
Verification Commands
After any installation, verify with:
# For MkDocs projects
mkdocs serve
# Visit http://127.0.0.1:8000/[project-name]/
# For skill tracker
cat ~/.claude/activity-logs/skill-usage.jsonl | tail -5Home Page Template
This skill creates a professional home page for intelligent textbooks with cover images optimized for social media sharing.
What This Skill Creates
1. docs/index.md - Home page with proper frontmatter metadata 2. docs/img/cover.png - AI-generated cover image (user generates externally) 3. Social media optimization - Open Graph and Twitter Card metadata
Prerequisites
- Existing MkDocs Material project (use
mkdocs-template.mdfirst if needed) - Access to an AI image generator (ChatGPT/DALL-E, Midjourney, or similar)
- Course/book description and key themes identified
Workflow
Step 1: Gather Book Information
Collect the following information from the user:
1. Book Title - The main title (e.g., "Automating Instructional Design") 2. Subtitle (optional) - A secondary tagline 3. Description - 1-2 sentence description for SEO and social sharing 4. Key Themes - 5-10 major topics/concepts covered in the book 5. Target Audience - Who the book is for 6. Color Palette - Primary colors for the book's branding 7. Visual Style - Modern, classic, technical, playful, etc.
Step 2: Identify Montage Elements
Based on the book's themes, identify visual elements for the cover montage. These should be concrete, visually distinct items that represent the book's content.
Common Element Categories
Technology/AI Themes:
- Neural network patterns, circuit traces
- Chat bubbles, prompt interfaces
- Geometric AI iconography
- Data flow visualizations
Education/Learning Themes:
- Lightbulb icons (insight)
- Book or graduation cap silhouettes
- Ascending steps or pathways
- Connected nodes (knowledge graphs)
Visualization/Data Themes:
- Chart elements (bar, line, pie)
- Network graphs with nodes and edges
- Timeline bars with markers
- Map outlines with data points
- Flowchart arrows and shapes
Process/Methodology Themes:
- Gear mechanisms
- Puzzle pieces
- Circular workflow arrows
- Checklist elements
Human/Interaction Themes:
- Abstract human silhouettes
- Cursor/touch indicators
- Slider controls, buttons
- Interactive UI elements
Step 3: Design the Cover Layout
Standard intelligent textbook cover layout:
+----------------------------------------------------------+
| |
| [Montage elements [Montage elements |
| distributed distributed |
| throughout] throughout] |
| |
| +------------------------+ |
| | | |
| | BOOK TITLE | (Semi-transparent |
| | (White Text) | dark overlay) |
| | | |
| +------------------------+ |
| |
| [More montage [More montage |
| elements] elements] |
| |
+----------------------------------------------------------+
Aspect Ratio: 1.91:1 (e.g., 1910x1000 pixels)Step 4: Generate the AI Image Prompt
Create a detailed prompt for the AI image generator. Follow this template:
A wide landscape book cover background (1.91:1 aspect ratio) for "[BOOK TITLE]".
[BACKGROUND DESCRIPTION]: Deep [PRIMARY COLOR]-to-[SECONDARY COLOR] gradient background.
[MONTAGE ELEMENTS]: A montage of [THEME] elements including:
- [Element 1 with visual description]
- [Element 2 with visual description]
- [Element 3 with visual description]
- [Continue for 6-10 elements]
[STYLE]: [VISUAL STYLE] design aesthetic with [ACCENT COLORS] accents.
[COMPOSITION]: Elements softly fade toward edges with subtle vignette, leaving center area darker/cleaner for white title text overlay.
[TECHNICAL]: Professional quality, high resolution. No text in image.Example Prompts by Topic
For Educational Technology Book:
A wide landscape book cover background (1.91:1 aspect ratio) for an educational technology textbook. Deep blue (#1a237e) to teal (#00695c) gradient background with a montage of EdTech elements: glowing neural network patterns suggesting AI, network graph visualizations with interconnected nodes, timeline bars with milestone markers, small data charts and graphs, flowchart arrows, animated particle trails, a stylized 6-level pyramid in graduated colors (purple to blue), interactive UI elements like sliders and toggle buttons, lightbulb icons representing insight, interconnected gears showing process. Modern flat design aesthetic with warm orange (#ff7043) and electric purple (#7c4dff) accents. Elements softly fade toward edges, leaving center darker for white title text overlay. Professional, tech-forward, educational mood. No text in image.For Data Science Book:
A wide landscape book cover background (1.91:1 aspect ratio) for a data science textbook. Dark navy (#0d1b2a) to deep purple (#1b0d2a) gradient background with a montage of data science elements: scatter plot visualizations, regression lines, decision tree branches, Python code snippets (stylized/blurred), Jupyter notebook cells, pandas dataframe grids, neural network layer diagrams, confusion matrix heatmaps, ROC curve shapes, bar and histogram silhouettes. Modern technical aesthetic with cyan (#00bcd4) and magenta (#e91e63) accent glows. Elements arranged as floating panels with subtle shadows, fading toward edges. Center area has darker overlay for white title text. Professional, analytical, modern mood. No text in image.For Business/Management Book:
A wide landscape book cover background (1.91:1 aspect ratio) for a business management textbook. Deep charcoal (#263238) to dark blue (#1a237e) gradient background with a montage of business elements: organizational chart hierarchies, strategy matrix grids, upward trending arrows, pie chart segments, Gantt chart bars, handshake silhouettes, target/bullseye icons, ascending bar graphs, connected stakeholder nodes, briefcase icons, growth curve lines. Clean corporate aesthetic with gold (#ffc107) and teal (#009688) accents. Elements distributed evenly with professional spacing, subtle fade toward edges. Center reserved for white title text with semi-transparent overlay. Professional, strategic, authoritative mood. No text in image.Step 5: Generate the Cover Image
1. Copy the generated prompt 2. Use an AI image generator:
- ChatGPT/DALL-E: Paste prompt directly
- Midjourney: Add
--ar 191:100for aspect ratio - Stable Diffusion: Use appropriate settings for 1910x1000
3. Generate 2-4 variations 4. Select the best result 5. Download at highest available resolution
Step 6: Add Title Text Overlay (Optional)
If adding title text directly to the image:
1. Use image editing software (Canva, Figma, Photoshop, GIMP) 2. Add semi-transparent dark rectangle in center (opacity 40-60%) 3. Add title text in white 4. Recommended fonts: Inter, Montserrat, Source Sans Pro, or system sans-serif 5. Export as PNG at 1910x1000 pixels minimum
Note: Many users prefer to let the image stand alone without baked-in text, using HTML/CSS overlays instead for flexibility.
Step 7: Save the Cover Image
Save the final image to the docs folder:
docs/img/cover.pngRecommended specifications:
- Format: PNG (for quality) or WebP (for size)
- Dimensions: 1910x1000 pixels minimum
- File size: Under 500KB for web performance
Step 8: Create the Home Page (docs/index.md)
Create or update docs/index.md with proper frontmatter:
---
title: {{BOOK_TITLE}}
description: {{BOOK_DESCRIPTION}}
image: /img/cover.png
og:image: /img/cover.png
twitter:image: /img/cover.png
hide:
- toc
---
<style>
.md-content__inner h1 {display: none !important;}
</style>
# Welcome
Welcome to **{{BOOK_TITLE}}**.
{{INTRODUCTORY_PARAGRAPH}}
## About This Book
{{BOOK_DESCRIPTION_EXPANDED}}
## Who This Book Is For
{{TARGET_AUDIENCE_DESCRIPTION}}
## How to Use This Book
Use the navigation menu to explore:
- **Chapters** - Main educational content
- **Learning Graph** - Interactive concept visualization
- **Simulations** - Interactive MicroSims for hands-on learning
- **Glossary** - Key terms and definitions
## Getting Started
Start with [Chapter 1](chapters/01/index.md) to begin your learning journey.Frontmatter Fields Explained
| Field | Purpose | Example |
|---|---|---|
title | Page title in browser tab and SEO | Automating Instructional Design |
description | SEO meta description, social sharing | Learn to create interactive educational simulations using AI |
image | Default social media image path | /img/cover.png |
og:image | Open Graph image (Facebook, LinkedIn) | /img/cover.png |
twitter:image | Twitter Card image | /img/cover.png |
hide: - toc | Hides table of contents on home page | - |
Step 9: Verify Social Media Preview
Test how the page appears when shared:
1. Facebook Debugger: https://developers.facebook.com/tools/debug/ 2. Twitter Card Validator: https://cards-dev.twitter.com/validator 3. LinkedIn Post Inspector: https://www.linkedin.com/post-inspector/
Enter your deployed site URL to preview social cards.
Step 10: Add Cover Image to Navigation (Optional)
To display the cover image prominently on the home page, add to docs/index.md:
<figure markdown>
{ width="100%" }
</figure>Or with a link wrapper:
[{ width="100%" }](chapters/01/index.md)Complete Example: docs/index.md
---
title: Automating Instructional Design
description: Learn to transform learning objectives into interactive MicroSims using AI-assisted tools
image: /img/cover.png
og:image: /img/cover.png
twitter:image: /img/cover.png
hide:
- toc
---
<style>
.md-content__inner h1 {display: none !important;}
</style>
# Welcome
Welcome to **Automating Instructional Design**, a hands-on course for educators and training professionals.
<figure markdown>
{ width="100%" }
</figure>
## About This Course
This intermediate-level course teaches you how to leverage AI-assisted tools to transform learning objectives into interactive educational simulations called MicroSims. Bridge the gap between abstract pedagogical goals and concrete, interactive learning experiences.
## Who This Course Is For
- K-12 Teachers
- Corporate Training Specialists
- Higher Education Faculty
- Instructional Designers
- Curriculum Developers
No programming experience required.
## Getting Started
Start with [Chapter 1: Foundations of Learning Objective Analysis](chapters/01/index.md).Troubleshooting
Image Not Appearing in Social Previews
1. Ensure image path starts with / (absolute from site root) 2. Verify image exists at docs/img/cover.png 3. Check image dimensions (minimum 1200x630 for best compatibility) 4. Clear social platform caches using their debug tools 5. Wait 24 hours for caches to refresh
Image Quality Issues
- Use PNG for sharp graphics and text
- Minimum 1910x1000 pixels
- If file size is too large, use WebP or optimize PNG
Frontmatter Not Working
- Ensure
---delimiters are on their own lines - No spaces before first
--- - YAML syntax must be valid (proper indentation, colons)
Quick Reference
# Minimal frontmatter for social sharing
---
title: Book Title
description: Brief description for search engines and social sharing
image: /img/cover.png
og:image: /img/cover.png
twitter:image: /img/cover.png
hide:
- toc
---Related Skills
mkdocs-template.md- Create new MkDocs project structurelearning-graph-viewer.md- Add interactive learning graphlinkedin-announcement-generator- Create social media announcements
Install Learning Graph Viewer
Overview
This skill installs a complete interactive graph visualization application into the /docs/sims/graph-viewer/ directory of an intelligent textbook project. The viewer provides an interactive way to explore learning graphs with features like node search, category filtering, and real-time statistics.
When to Use This Skill
Use this skill when:
- A learning graph has been generated (learning-graph.json exists in /docs/learning-graph/)
- The textbook needs an interactive visualization tool for exploring concept dependencies
- Students or instructors need to filter, search, and analyze the learning graph structure
Prerequisites:
/docs/learning-graph/learning-graph.jsonmust exist- The JSON file must have metadata with a
titlefield - The JSON file must have proper
classifierNamevalues in groups (see Step 3.5) - MkDocs project structure must be in place
Installation Workflow
Step 1: Verify Prerequisites
Before installation, verify that the learning graph JSON file exists:
ls docs/learning-graph/learning-graph.jsonIf the file doesn't exist, use the learning-graph-generator skill first to create the learning graph.
Step 2: Create Directory Structure
Create the graph-viewer directory:
mkdir -p docs/sims/graph-viewerStep 3: Create main.html
Create docs/sims/graph-viewer/main.html with the following structure:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Learning Graph Viewer for TITLE</title>
<script src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
<link rel="stylesheet" href="local.css">
</head>
<body>
<div class="container">
<div class="sidebar" id="sidebar">
<div class="sidebar-header">
<h4>Learning Graph for TITLE</h4>
<button id="toggle-sidebar" class="toggle-btn" title="Toggle Sidebar">☰</button>
</div>
<div class="sidebar-content" id="sidebar-content">
<div class="search-container">
<label for="search">Search Concepts:</label>
<input type="text" id="search" placeholder="Type to search...">
<div id="search-results" class="search-results"></div>
</div>
<div class="legend-container">
<h5>Categories</h5>
<div class="legend-controls">
<button id="check-all" class="legend-btn">Check All</button>
<button id="uncheck-all" class="legend-btn">Uncheck All</button>
</div>
<div id="legend"></div>
</div>
<div class="stats-container">
<h5>Statistics</h5>
<div id="stats">
<p>Visible Nodes: <span id="visible-nodes">0</span></p>
<p>Visible Edges: <span id="visible-edges">0</span></p>
<p>Foundational: <span id="foundational-nodes">0</span></p>
</div>
</div>
</div>
</div>
<div class="graph-container" id="graph-container">
<div id="network"></div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>Replace "TITLE" with the course title from learning-graph.json metadata.
Step 4: Create local.css
Create docs/sims/graph-viewer/local.css with all sidebar and layout styling:
/* Learning Graph Viewer Styles */
/* ================================
RESET AND BASE STYLES
================================ */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
background-color: #f5f5f5;
overflow: hidden;
}
/* ================================
MAIN LAYOUT CONTAINER
Uses flexbox for sidebar + graph layout
================================ */
.container {
display: flex;
height: 100vh;
width: 100vw;
}
/* ================================
SIDEBAR STYLES
Collapsible sidebar with search, legend, and stats
================================ */
.sidebar {
/* Width settings - adjust for label wrapping */
width: 200px;
min-width: 200px;
/* Visual styling */
background-color: #fff;
border-right: 1px solid #ddd;
/* Flexbox for internal layout */
display: flex;
flex-direction: column;
/* Smooth collapse animation */
transition: width 0.3s ease, min-width 0.3s ease;
overflow: hidden;
}
/* Collapsed state - narrow width shows only toggle button */
.sidebar.collapsed {
width: 50px;
min-width: 50px;
}
/* ================================
SIDEBAR HEADER
Contains title and toggle button
================================ */
.sidebar-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px;
background-color: #2196F3; /* Blue header bar */
color: white;
}
.sidebar-header h4 {
font-size: 14px;
font-weight: 600;
margin: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis; /* Truncate long titles */
}
/* Hide title when collapsed */
.sidebar.collapsed .sidebar-header h4 {
display: none;
}
/* ================================
TOGGLE BUTTON
Hamburger menu icon for collapse/expand
================================ */
.toggle-btn {
background: none;
border: none;
color: white;
font-size: 20px;
cursor: pointer;
padding: 5px;
border-radius: 4px;
}
.toggle-btn:hover {
background-color: rgba(255,255,255,0.2);
}
/* ================================
SIDEBAR CONTENT
Scrollable area containing search, legend, stats
================================ */
.sidebar-content {
flex: 1;
overflow-y: auto;
padding: 15px;
}
/* ================================
SEARCH CONTAINER STYLES
Type-ahead search for finding concepts
================================ */
.search-container {
margin-bottom: 20px;
}
.search-container label {
display: block;
font-weight: 600;
margin-bottom: 8px;
color: #333;
}
.search-container input {
width: 100%;
padding: 10px 12px;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 14px;
transition: border-color 0.2s;
}
.search-container input:focus {
outline: none;
border-color: #2196F3;
box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1); /* Blue focus ring */
}
/* ================================
SEARCH RESULTS DROPDOWN
Positioned absolutely below search input
================================ */
.search-results {
display: none; /* Hidden by default */
position: absolute;
width: calc(100% - 30px); /* Account for sidebar padding */
background: white;
border: 1px solid #ddd;
border-radius: 6px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
max-height: 300px;
overflow-y: auto;
z-index: 100; /* Above other content */
margin-top: 4px;
}
.search-result-item {
padding: 10px 12px;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #eee;
}
.search-result-item:last-child {
border-bottom: none;
}
.search-result-item:hover {
background-color: #f5f5f5;
}
.result-label {
font-weight: 500;
color: #333;
}
/* Category badge in search results */
.result-category {
font-size: 11px;
padding: 3px 8px;
border-radius: 12px;
color: #333;
}
/* ================================
LEGEND CONTAINER STYLES
Category filtering with checkboxes
================================ */
.legend-container {
margin-bottom: 20px;
}
.legend-container h5 {
font-weight: 600;
margin-bottom: 10px;
color: #333;
}
/* Check All / Uncheck All buttons */
.legend-controls {
display: flex;
gap: 8px;
margin-bottom: 12px;
}
.legend-btn {
flex: 1;
padding: 6px 10px;
font-size: 12px;
border: 1px solid #ddd;
background: #fff;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s;
}
.legend-btn:hover {
background: #f0f0f0;
border-color: #bbb;
}
/* Legend items container - scrollable for many categories */
#legend {
max-height: 400px;
overflow-y: auto;
}
/* Individual legend item (checkbox + color + label) */
.legend-item {
display: flex;
align-items: center;
padding: 6px 0;
gap: 8px;
}
.legend-item input[type="checkbox"] {
width: 16px;
height: 16px;
cursor: pointer;
}
/* Color swatch box */
.color-box {
width: 20px;
height: 20px;
border-radius: 4px;
border: 1px solid rgba(0,0,0,0.1);
flex-shrink: 0; /* Don't shrink color box */
}
.legend-item label {
font-size: 13px;
color: #555;
cursor: pointer;
flex: 1;
}
/* ================================
STATISTICS CONTAINER STYLES
Shows counts of visible nodes, edges, foundational
================================ */
.stats-container {
background-color: #f9f9f9;
padding: 12px;
border-radius: 6px;
}
.stats-container h5 {
font-weight: 600;
margin-bottom: 10px;
color: #333;
}
#stats p {
font-size: 13px;
color: #666;
margin-bottom: 6px;
}
#stats span {
font-weight: 600;
color: #2196F3; /* Blue accent for numbers */
}
/* ================================
GRAPH CONTAINER STYLES
Main visualization area
================================ */
.graph-container {
flex: 1; /* Take remaining space */
position: relative;
background-color: aliceblue; /* Light blue background */
}
#network {
width: 100%;
height: 100%;
}
/* ================================
RESPONSIVE ADJUSTMENTS
Mobile-friendly sidebar widths
================================ */
@media (max-width: 768px) {
.sidebar {
width: 250px;
min-width: 250px;
}
.sidebar.collapsed {
width: 40px;
min-width: 40px;
}
}Step 5: Create script.js
Create docs/sims/graph-viewer/script.js with the visualization logic:
// Learning Graph Viewer Script
// Loads and displays an interactive learning graph using vis-network
let network = null;
let allNodes = [];
let allEdges = [];
let groups = {};
let visibleGroups = new Set();
// Load the learning graph data
async function loadGraph() {
try {
const response = await fetch('../../learning-graph/learning-graph.json');
const data = await response.json();
allNodes = data.nodes || [];
allEdges = data.edges || [];
groups = data.groups || {};
// Initialize all groups as visible
Object.keys(groups).forEach(g => visibleGroups.add(g));
initializeNetwork();
buildLegend();
updateStats();
setupSearch();
setupControls();
} catch (error) {
console.error('Error loading learning graph:', error);
document.getElementById('network').innerHTML =
'<p style="color: red; padding: 20px;">Error loading learning graph. Make sure learning-graph.json exists.</p>';
}
}
// Initialize the vis-network visualization
function initializeNetwork() {
const container = document.getElementById('network');
// Create nodes DataSet - colors are handled by the groups option
const nodes = new vis.DataSet(allNodes);
// Create edges DataSet
const edges = new vis.DataSet(allEdges.map(edge => ({
...edge,
arrows: 'to',
color: { color: '#888', opacity: 0.6 }
})));
const data = { nodes, edges };
// Build vis-network groups configuration from JSON groups
const visGroups = {};
Object.entries(groups).forEach(([groupId, groupInfo]) => {
visGroups[groupId] = {
color: {
background: groupInfo.color || 'lightgray',
border: groupInfo.color || 'lightgray',
highlight: {
background: groupInfo.color || 'lightgray',
border: '#333'
},
hover: {
background: groupInfo.color || 'lightgray',
border: '#666'
}
},
font: {
color: groupInfo.font?.color || 'black'
}
};
});
const options = {
groups: visGroups,
layout: {
randomSeed: 42,
improvedLayout: true
},
physics: {
enabled: true,
solver: 'forceAtlas2Based',
forceAtlas2Based: {
gravitationalConstant: -50,
centralGravity: 0.01,
springLength: 100,
springConstant: 0.08,
damping: 0.4,
avoidOverlap: 0.5
},
stabilization: {
enabled: true,
iterations: 1000,
updateInterval: 25
}
},
nodes: {
shape: 'box',
margin: 4,
font: {
size: 14,
face: 'Arial'
},
borderWidth: 2,
shadow: true
},
edges: {
smooth: {
type: 'cubicBezier',
forceDirection: 'horizontal',
roundness: 0.4
},
width: 1.5
},
interaction: {
hover: true,
tooltipDelay: 200,
zoomView: true,
dragView: true
}
};
network = new vis.Network(container, data, options);
// Handle node selection
network.on('selectNode', function(params) {
if (params.nodes.length > 0) {
const nodeId = params.nodes[0];
const node = allNodes.find(n => n.id === nodeId);
if (node) {
highlightNode(nodeId);
}
}
});
}
// Build the category legend
function buildLegend() {
const legendContainer = document.getElementById('legend');
legendContainer.innerHTML = '';
Object.entries(groups).forEach(([groupId, groupInfo]) => {
const count = allNodes.filter(n => n.group === groupId).length;
const item = document.createElement('div');
item.className = 'legend-item';
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.id = `group-${groupId}`;
checkbox.checked = true;
checkbox.addEventListener('change', () => toggleGroup(groupId, checkbox.checked));
const colorBox = document.createElement('span');
colorBox.className = 'color-box';
colorBox.style.backgroundColor = groupInfo.color || 'lightgray';
const label = document.createElement('label');
label.htmlFor = `group-${groupId}`;
label.textContent = `${groupInfo.classifierName || groupId} (${count})`;
item.appendChild(checkbox);
item.appendChild(colorBox);
item.appendChild(label);
legendContainer.appendChild(item);
});
}
// Toggle visibility of a category group
function toggleGroup(groupId, visible) {
if (visible) {
visibleGroups.add(groupId);
} else {
visibleGroups.delete(groupId);
}
updateVisibility();
}
// Update node and edge visibility based on selected groups
function updateVisibility() {
const visibleNodeIds = new Set(
allNodes.filter(n => visibleGroups.has(n.group)).map(n => n.id)
);
const nodes = network.body.data.nodes;
const edges = network.body.data.edges;
// Update node visibility
allNodes.forEach(node => {
const isVisible = visibleGroups.has(node.group);
nodes.update({
id: node.id,
hidden: !isVisible
});
});
// Update edge visibility (hide if either endpoint is hidden)
allEdges.forEach(edge => {
const isVisible = visibleNodeIds.has(edge.from) && visibleNodeIds.has(edge.to);
edges.update({
id: edge.id || `${edge.from}-${edge.to}`,
hidden: !isVisible
});
});
updateStats();
}
// Update statistics display
function updateStats() {
const visibleNodeIds = new Set(
allNodes.filter(n => visibleGroups.has(n.group)).map(n => n.id)
);
const visibleEdgeCount = allEdges.filter(
e => visibleNodeIds.has(e.from) && visibleNodeIds.has(e.to)
).length;
// Count foundational nodes (nodes with no outgoing dependencies)
const nodesWithDeps = new Set(allEdges.map(e => e.from));
const foundationalCount = allNodes.filter(
n => !nodesWithDeps.has(n.id) && visibleGroups.has(n.group)
).length;
document.getElementById('visible-nodes').textContent = visibleNodeIds.size;
document.getElementById('visible-edges').textContent = visibleEdgeCount;
document.getElementById('foundational-nodes').textContent = foundationalCount;
}
// Setup search functionality
function setupSearch() {
const searchInput = document.getElementById('search');
const resultsContainer = document.getElementById('search-results');
searchInput.addEventListener('input', function() {
const query = this.value.toLowerCase().trim();
resultsContainer.innerHTML = '';
if (query.length < 2) {
resultsContainer.style.display = 'none';
return;
}
const matches = allNodes.filter(n =>
n.label.toLowerCase().includes(query)
).slice(0, 10);
if (matches.length === 0) {
resultsContainer.style.display = 'none';
return;
}
matches.forEach(node => {
const item = document.createElement('div');
item.className = 'search-result-item';
const groupInfo = groups[node.group] || {};
item.innerHTML = `
<span class="result-label">${node.label}</span>
<span class="result-category" style="background-color: ${groupInfo.color || 'lightgray'}">
${groupInfo.classifierName || node.group}
</span>
`;
item.addEventListener('click', () => {
selectNode(node.id);
searchInput.value = node.label;
resultsContainer.style.display = 'none';
});
resultsContainer.appendChild(item);
});
resultsContainer.style.display = 'block';
});
// Hide results when clicking outside
document.addEventListener('click', function(e) {
if (!searchInput.contains(e.target) && !resultsContainer.contains(e.target)) {
resultsContainer.style.display = 'none';
}
});
}
// Select and focus on a node
function selectNode(nodeId) {
network.selectNodes([nodeId]);
network.focus(nodeId, {
scale: 1.2,
animation: {
duration: 500,
easingFunction: 'easeInOutQuad'
}
});
highlightNode(nodeId);
}
// Highlight a node and its connections
function highlightNode(nodeId) {
const connectedNodes = network.getConnectedNodes(nodeId);
const allConnected = [nodeId, ...connectedNodes];
// Reset all nodes to normal opacity
const nodes = network.body.data.nodes;
allNodes.forEach(node => {
const isConnected = allConnected.includes(node.id);
nodes.update({
id: node.id,
opacity: isConnected ? 1 : 0.3
});
});
// Reset opacity after a delay
setTimeout(() => {
allNodes.forEach(node => {
nodes.update({
id: node.id,
opacity: 1
});
});
}, 3000);
}
// Setup control buttons
function setupControls() {
// Toggle sidebar
document.getElementById('toggle-sidebar').addEventListener('click', function() {
const sidebar = document.getElementById('sidebar');
const content = document.getElementById('sidebar-content');
sidebar.classList.toggle('collapsed');
content.style.display = sidebar.classList.contains('collapsed') ? 'none' : 'block';
});
// Check all groups
document.getElementById('check-all').addEventListener('click', function() {
Object.keys(groups).forEach(groupId => {
visibleGroups.add(groupId);
document.getElementById(`group-${groupId}`).checked = true;
});
updateVisibility();
});
// Uncheck all groups
document.getElementById('uncheck-all').addEventListener('click', function() {
Object.keys(groups).forEach(groupId => {
visibleGroups.delete(groupId);
document.getElementById(`group-${groupId}`).checked = false;
});
updateVisibility();
});
}
// Initialize when DOM is ready
document.addEventListener('DOMContentLoaded', loadGraph);Step 6: Create index.md
Create docs/sims/graph-viewer/index.md with documentation:
# Learning Graph Viewer
This interactive viewer allows you to explore the learning graph for the course.
## Features
- **Search**: Type in the search box to find specific concepts
- **Category Filtering**: Use checkboxes to show/hide concept categories
- **Interactive Navigation**: Click and drag to explore, scroll to zoom
- **Statistics**: View real-time counts of visible nodes and edges
## Using the Viewer
1. **Search for Concepts**: Start typing in the search box to find concepts. Click on a result to focus on that node.
2. **Filter by Category**: Use the category checkboxes in the sidebar to show or hide groups of related concepts. Use "Check All" or "Uncheck All" for bulk operations.
3. **Navigate the Graph**:
- Drag to pan around the graph
- Scroll to zoom in and out
- Click on a node to select it and highlight its connections
4. **View Statistics**: The sidebar shows counts of visible nodes, edges, and foundational concepts.
## Graph Structure
- **Foundational Concepts** (left side): Prerequisites with no dependencies
- **Advanced Concepts** (right side): Topics that build on multiple prerequisites
- **Edges**: Arrows point from a concept to its prerequisites
## Launch the Viewer
[Open Learning Graph Viewer](./main.html){ .md-button .md-button--primary }
<iframe src="./main.html" width="100%" height="600px" frameborder="0"></iframe>Step 7: Verify classifierName Values in JSON (IMPORTANT)
The learning-graph.json file must have human-readable classifierName values in the groups section. This is critical for the legend to display correctly.
Check the groups section of learning-graph.json:
"groups": {
"FOUND": {
"classifierName": "Foundation Concepts", // CORRECT - human readable
"color": "LightCoral"
},
"BLOOM": {
"classifierName": "BLOOM", // WRONG - just the ID, not human readable
"color": "PeachPuff"
}
}If any classifierName values are just the group ID (like "BLOOM", "VISUA"), update them to be human-readable (like "Bloom's Taxonomy", "Visualization Types").
Common taxonomy mappings:
| Group ID | classifierName |
|---|---|
| FOUND | Foundation Concepts |
| BLOOM | Bloom's Taxonomy |
| VISUA | Visualization Types |
| LIBRA | Libraries & Tools |
| SPECI | Specification |
| COGNI | Cognitive Science |
| AUDIE | Audience Adaptation |
| EVALU | Evaluation & Testing |
| ITERA | Iteration & Workflow |
| ACCES | Accessibility |
| DEPLO | Deployment |
| CAPST | Capstone |
Step 8: Update Title in main.html
Replace the "TITLE" placeholder in main.html with the course title:
1. Extract title from learning-graph.json metadata 2. In docs/sims/graph-viewer/main.html, replace all instances of "TITLE" with the actual course title 3. This appears in two locations:
- The
<title>tag:<title>Learning Graph Viewer for TITLE</title> - The page heading:
<h4>Learning Graph for TITLE</h4>
Step 9: Update MkDocs Navigation (Optional)
If the user wants the graph viewer in the site navigation, add it to mkdocs.yml:
nav:
- MicroSims:
- Graph Viewer: sims/graph-viewer/index.mdStep 10: Inform the User
Provide the user with instructions to test the installation:
1. Run mkdocs serve to start the local development server 2. Navigate to the appropriate URL based on their repository name:
- Format:
http://localhost:8000/REPO_NAME/sims/graph-viewer/main.html
3. Alternatively, access it through the MkDocs site menu if added to navigation
---
vis-network Options Reference
The viewer uses these vis-network configuration options:
Groups Configuration
Purpose: Maps learning graph taxonomy groups to vis-network colors so legend and nodes match.
const visGroups = {};
Object.entries(groups).forEach(([groupId, groupInfo]) => {
visGroups[groupId] = {
color: {
background: groupInfo.color || 'lightgray', // Node fill color
border: groupInfo.color || 'lightgray', // Node border color
highlight: {
background: groupInfo.color || 'lightgray',
border: '#333' // Dark border when selected
},
hover: {
background: groupInfo.color || 'lightgray',
border: '#666' // Medium border on hover
}
},
font: {
color: groupInfo.font?.color || 'black' // Label text color
}
};
});Layout Options
Purpose: Controls initial node positioning. Uses physics-based layout (NOT hierarchical).
layout: {
randomSeed: 42, // Consistent initial positions across reloads
improvedLayout: true // Better initial spread before physics kicks in
}Important: Do NOT use hierarchical layout for learning graphs - it doesn't work well with complex DAGs.
Physics Options
Purpose: Controls force-directed graph simulation for node positioning.
physics: {
enabled: true,
solver: 'forceAtlas2Based', // Best solver for large graphs
forceAtlas2Based: {
gravitationalConstant: -50, // Repulsion force (negative = push apart)
centralGravity: 0.01, // Pull toward center (low = spread out)
springLength: 100, // Ideal edge length in pixels
springConstant: 0.08, // Edge spring stiffness
damping: 0.4, // Velocity damping (higher = slower settling)
avoidOverlap: 0.5 // Node overlap prevention (0-1)
},
stabilization: {
enabled: true,
iterations: 1000, // Stabilization iterations before render
updateInterval: 25 // Progress update frequency (ms)
}
}Node Options
Purpose: Visual appearance of concept nodes.
nodes: {
shape: 'box', // Rectangular nodes (good for text labels)
margin: 4, // Padding inside node box
font: {
size: 14, // Label font size
face: 'Arial' // Font family
},
borderWidth: 2, // Node border thickness
shadow: true // Drop shadow for depth
}Edge Options
Purpose: Visual appearance of dependency arrows.
edges: {
smooth: {
type: 'cubicBezier', // Curved edges
forceDirection: 'horizontal', // Curves bend horizontally
roundness: 0.4 // Curve intensity (0-1)
},
width: 1.5 // Line thickness
}Note on edge creation: Edges are created with arrows and muted color:
edges = new vis.DataSet(allEdges.map(edge => ({
...edge,
arrows: 'to', // Arrowhead at target
color: { color: '#888', opacity: 0.6 } // Gray, semi-transparent
})));Interaction Options
Purpose: User interaction controls.
interaction: {
hover: true, // Enable hover effects
tooltipDelay: 200, // Delay before tooltip appears (ms)
zoomView: true, // Allow scroll-to-zoom
dragView: true // Allow click-and-drag panning
}---
CSS Reference
Layout Classes
| Class | Purpose |
|---|---|
.container | Flex container holding sidebar + graph (100vw × 100vh) |
.sidebar | Left sidebar (200px width, collapsible to 50px) |
.sidebar.collapsed | Collapsed state styling |
.sidebar-content | Scrollable content area inside sidebar |
.graph-container | Main graph area (flex: 1, fills remaining space) |
#network | vis-network canvas (100% × 100%) |
Sidebar Header Classes
| Class | Purpose |
|---|---|
.sidebar-header | Blue header bar with title and toggle |
.sidebar-header h4 | Title text (truncates with ellipsis) |
.toggle-btn | Hamburger menu button (☰) |
Search Classes
| Class | Purpose |
|---|---|
.search-container | Wrapper for search input and results |
.search-results | Dropdown with matching concepts |
.search-result-item | Individual search result row |
.result-label | Concept name in search result |
.result-category | Category badge in search result |
Legend Classes
| Class | Purpose |
|---|---|
.legend-container | Wrapper for category legend |
.legend-controls | Check All / Uncheck All buttons |
.legend-btn | Individual control button |
#legend | Container for legend items (scrollable) |
.legend-item | Single category row (checkbox + color + label) |
.color-box | 20×20px color swatch |
Statistics Classes
| Class | Purpose |
|---|---|
.stats-container | Gray background box for stats |
#stats | Container for stat paragraphs |
#visible-nodes | Span for node count (blue text) |
#visible-edges | Span for edge count (blue text) |
#foundational-nodes | Span for foundational count (blue text) |
Key CSS Variables/Colors
| Element | Color | Usage |
|---|---|---|
| Sidebar header | #2196F3 | Blue Material Design primary |
| Focus ring | rgba(33, 150, 243, 0.1) | Light blue focus glow |
| Stats numbers | #2196F3 | Blue accent for statistics |
| Graph background | aliceblue | Light blue canvas background |
| Borders | #ddd | Light gray for borders |
| Text primary | #333 | Dark gray for headings |
| Text secondary | #555 / #666 | Medium gray for labels |
---
Common Issues and Fixes
Issue 1: Legend colors don't match node colors
Symptom: When filtering by category, the visible nodes are a different color than the legend swatch.
Cause: The script must pass the groups configuration to vis-network's groups option.
Fix: Ensure script.js builds visGroups from JSON and passes to options:
const options = {
groups: visGroups, // This is required!
// ... other options
};Issue 2: Legend shows group IDs instead of readable names
Symptom: The legend shows "FOUND", "BLOOM" instead of "Foundation Concepts", "Bloom's Taxonomy".
Cause: The classifierName values in learning-graph.json are set to the group IDs.
Fix: Update the groups section in learning-graph.json to have proper classifierName values.
Issue 3: Hierarchical layout doesn't work well
Symptom: The graph layout is messy or nodes overlap badly.
Cause: Hierarchical layout doesn't work well with DAGs that have complex dependency structures.
Fix: Use physics-based layout with forceAtlas2Based solver (as shown in script.js).
Issue 4: Graph takes too long to stabilize
Symptom: The graph keeps moving for a long time before settling.
Fix: Adjust physics parameters:
- Increase
damping(e.g., 0.4 → 0.6) for faster settling - Decrease
stabilization.iterationsfor quicker initial render - Increase
springConstantfor stiffer edges
---
Viewer Features
The installed graph viewer provides:
Search Functionality:
- Type-ahead search with dropdown results
- Shows category information for each node
- Focuses and selects matching nodes in the visualization
Category Filtering:
- Sidebar legend with color-coded categories
- Checkboxes to show/hide specific taxonomy groups
- "Check All" and "Uncheck All" bulk operations
- Collapsible sidebar for expanded viewing
Real-time Statistics:
- Visible node count
- Visible edge count
- Foundational node count (concepts with no dependencies)
Interactive Visualization:
- vis-network graph with physics simulation
- Color-coded nodes by taxonomy category
- Directed edges showing concept dependencies
- Zoomable and draggable interface
- Node highlight on selection (dims unconnected nodes)
---
Technical Details
File Structure:
docs/sims/graph-viewer/
├── main.html # Main application HTML
├── script.js # JavaScript logic for visualization
├── local.css # Styling for the viewer
└── index.md # Documentation page with iframe embedDependencies:
- vis-network.js (loaded from CDN:
https://unpkg.com/vis-network/standalone/umd/vis-network.min.js) - learning-graph.json (loaded from
../../learning-graph/learning-graph.json)
Data Path: The script.js file loads the learning graph from a relative path: ../../learning-graph/learning-graph.json. This assumes the standard intelligent textbook structure where /docs/sims/ and /docs/learning-graph/ are siblings.
Install MkDocs Template
This skill creates a complete MkDocs Material project structure optimized for intelligent textbooks.
What This Skill Creates
1. mkdocs.yml - Complete configuration with all Material theme options 2. docs/css/extra.css - Custom CSS with branding color variables 3. docs/img/ - Directory for logo and favicon 4. plugins/ - Social override plugin for custom social media cards 5. setup.py - Plugin installation configuration 6. docs/index.md - Home page template
Prerequisites
- Conda (Miniconda or Anaconda) installed
- Git repository initialized with remote origin configured
- GitHub repository created (for GitHub Pages deployment)
Workflow
Step 1: Create Conda Environment
Create a new Conda environment named mkdocs with Python 3:
conda create -n mkdocs python=3.11 -yStep 2: Activate Environment and Install Dependencies
Activate the environment and install MkDocs with Material theme:
conda activate mkdocs
pip install mkdocs mkdocs-material mkdocs-material-extensions pillow cairosvgThe additional packages (pillow, cairosvg) are required for social media card generation.
Step 3: Gather Project Information
Before creating files, collect the following information from the user:
1. site_name - The title of the textbook (e.g., "Introduction to Machine Learning") 2. site_description - A brief description for SEO and social sharing 3. site_author - Author name(s) 4. repo_name - GitHub repository display name (default: "GitHub Repo") 5. site_url - Full URL where the site will be hosted (e.g., "https://username.github.io/repo-name/") 6. repo_url - GitHub repository URL 7. primary_color_rgb - Primary brand color as RGB values (default: 218, 120, 87 - Anthropic brown) 8. google_analytics_id - Optional Google Analytics property ID
Step 4: Create Directory Structure
Create the following directory structure in the current working directory:
project-root/
├── docs/
│ ├── css/
│ │ └── extra.css
│ ├── img/
│ │ ├── logo.png (placeholder - user must provide)
│ │ └── favicon.ico (placeholder - user must provide)
│ ├── chapters/
│ │ └── index.md
│ ├── learning-graph/
│ │ └── index.md
│ ├── sims/
│ │ └── index.md
│ └── index.md
├── plugins/
│ ├── __init__.py
│ └── social_override.py
├── mkdocs.yml
└── setup.pyStep 5: Create mkdocs.yml
Use the template from assets/mkdocs-template.yml as the base. Replace placeholders with user-provided values:
{{SITE_NAME}}- site_name{{SITE_DESCRIPTION}}- site_description{{SITE_AUTHOR}}- site_author{{REPO_NAME}}- repo_name{{SITE_URL}}- site_url{{REPO_URL}}- repo_url{{GOOGLE_ANALYTICS_ID}}- google_analytics_id (remove analytics section if not provided)
Step 6: Create extra.css
Use the template from assets/extra.css as the base. Replace the RGB color values with user-provided primary_color_rgb if different from default.
Step 7: Create Social Override Plugin
Copy the following files from assets:
assets/plugins/__init__.py→plugins/__init__.pyassets/plugins/social_override.py→plugins/social_override.pyassets/setup.py→setup.py
Step 8: Create Starter Content Files
Create minimal starter files for each directory:
docs/index.md:
# Welcome to {{SITE_NAME}}
{{SITE_DESCRIPTION}}
## Getting Started
This intelligent textbook is built with MkDocs Material theme.
## Navigation
Use the navigation menu on the left to explore chapters and content.docs/chapters/index.md:
# Chapters
This section contains the main chapter content of the textbook.docs/learning-graph/index.md:
# Learning Graph
This section contains the learning graph visualization and concept dependencies.docs/sims/index.md:
# Interactive Simulations
This section contains MicroSims - interactive educational simulations.Step 9: Install the Social Override Plugin
After creating all files, install the social_override plugin in editable mode:
pip install -e .Step 10: Build the Site
Build the static site to verify everything is configured correctly:
mkdocs buildThis creates a site/ directory with the generated HTML. Check for any build warnings or errors.
Step 11: Test Locally (Optional)
To preview the site locally before deploying:
mkdocs serveThe site will be accessible at http://localhost:8000
Step 12: Deploy to GitHub Pages
Deploy the site to GitHub Pages:
mkdocs gh-deployThis command: 1. Builds the site 2. Creates/updates the gh-pages branch 3. Pushes to GitHub 4. Configures GitHub Pages to serve from that branch
Step 13: Provide the GitHub Pages URL
After deployment, provide the user with the live site URL:
https://{{GITHUB_USERNAME}}.github.io/{{REPO_NAME}}/For example, if the repo_url is https://github.com/dmccreary/my-textbook, the site URL would be:
https://dmccreary.github.io/my-textbook/Important: The site may take 1-2 minutes to become available after the first deployment. Subsequent deployments are usually faster.
Step 14: Verify Deployment
Instruct the user to:
1. Visit the GitHub Pages URL 2. Check that the home page loads correctly 3. Verify navigation works 4. Test on mobile devices for responsive layout
MkDocs Material Features Included
The template includes these Material theme features:
Navigation
navigation.expand- Expandable navigation sectionsnavigation.path- Breadcrumb navigation pathnavigation.prune- Prune inactive navigation itemsnavigation.indexes- Section index pagesnavigation.top- Back to top buttonnavigation.footer- Previous/next page links in footertoc.follow- Table of contents follows scroll
Content
content.code.copy- Copy button for code blockscontent.action.edit- Edit on GitHub button
Plugins
search- Full-text searchsocial- Social media card generationsocial_override- Custom social media images per page
Markdown Extensions
md_in_html- Markdown inside HTML blocksadmonition- Callout boxes (note, warning, tip, etc.)attr_list- Add HTML attributes to elementspymdownx.details- Collapsible content blockspymdownx.superfences- Enhanced code fencingpymdownx.highlight- Syntax highlighting with line numbers
Customizing Social Media Cards
To use a custom social media image for any page, add frontmatter:
---
title: My Page Title
image: img/my-custom-social-card.png
---
# Page Content HereThe social_override plugin will use the custom image instead of the auto-generated one.
Logo and Favicon
After running the skill, the user must provide:
1. docs/img/logo.png - Site logo (recommended: 50x50px) 2. docs/img/favicon.ico - Browser favicon
Quick Reference - All Commands
Here is the complete sequence of commands for reference:
# Step 1: Create Conda environment
conda create -n mkdocs python=3.11 -y
# Step 2: Activate and install dependencies
conda activate mkdocs
pip install mkdocs mkdocs-material mkdocs-material-extensions pillow cairosvg
# Steps 3-8: Create files (done by Claude)
# Step 9: Install social_override plugin
pip install -e .
# Step 10: Build the site
mkdocs build
# Step 11: Test locally (optional)
mkdocs serve
# Step 12: Deploy to GitHub Pages
mkdocs gh-deploy
# Step 13: Access your site at:
# https://<username>.github.io/<repo-name>/Reactivating the Environment
When returning to work on the textbook in a new terminal session:
conda activate mkdocsNotes
- The template uses a custom primary color defined in CSS rather than Material's built-in palette
- Google Analytics is optional - remove the
analyticssection from mkdocs.yml if not needed - The edit_uri points to the
blob/master/docspath - adjust if using a different branch - The Conda environment is reusable across multiple MkDocs projects
- First deployment may take 1-2 minutes to appear on GitHub Pages
Install Skill Tracker
Overview
This skill automates the installation of a global skill tracking system for Claude Code. The system uses Claude Code hooks installed in ~/.claude/ to automatically log all skill invocations across all projects, including their duration, token usage, and the prompts that triggered them. This data enables pattern analysis to identify frequently repeated workflows that could become new skills.
Key Feature: Global installation means skill usage is tracked across all your Claude Code projects in a single centralized log, making it easy to analyze your total skill usage patterns and costs.
When to Use This Skill
Use this skill when:
- Setting up skill usage tracking that works across all your Claude Code projects
- Wanting to analyze which skills are used most frequently across your entire workflow
- Measuring how long each skill takes to identify optimization opportunities
- Monitoring API costs and token usage across all skill executions
- Identifying time-consuming skills that may need optimization
- Discovering patterns in work that could be automated with new skills
- Tracking productivity gains and cost efficiency from skill automation
- Understanding prompt cache effectiveness and optimization opportunities
Why Timing Matters: Understanding how long skills take helps you:
- Identify slow skills that need optimization
- Estimate total time saved through automation
- Make informed decisions about which skills to invest in improving
- Track productivity improvements over time
Installation Workflow
Step 1: Create Global Directory Structure
Create the necessary directories in your home .claude folder:
mkdir -p ~/.claude/hooks ~/.claude/scripts ~/.claude/activity-logsStep 2: Install Hook Scripts
Copy the hook scripts from this skill's scripts/ directory to ~/.claude/hooks/:
- track-prompts.sh - Logs user prompts with timestamps and session IDs
- track-skill-start.sh - Logs when skills begin execution
- track-skill-end.sh - Logs skill completion and calculates duration
Make the hook scripts executable:
chmod +x ~/.claude/hooks/*.shStep 3: Install Analysis Scripts
Copy the analysis scripts from this skill's scripts/ directory to ~/.claude/scripts/:
- analyze-skills.py - Processes logs and generates usage reports
- show-skill-tokens.sh - Displays token usage and cost metrics
Make the analysis scripts executable:
chmod +x ~/.claude/scripts/analyze-skills.py
chmod +x ~/.claude/scripts/show-skill-tokens.shStep 4: Configure Global Hooks
Copy the settings.json template from this skill's assets/ directory to ~/.claude/settings.json. This configuration registers three hooks that will run for all projects:
- UserPromptSubmit - Captures all user prompts
- PreToolUse (Skill matcher) - Logs skill start times
- PostToolUse (Skill matcher) - Logs skill completion times
Important: If you already have a ~/.claude/settings.json file, merge the hooks configuration rather than overwriting.
Step 5: Add Documentation
Copy the README.md from this skill's assets/ directory to ~/.claude/README.md. This provides documentation on:
- What data gets tracked
- How the tracking system works
- How to analyze the logs
- Customization options
- Troubleshooting guide
Step 6: Verify Installation
Confirm all files are in place:
ls -la ~/.claude/hooks/
ls -la ~/.claude/scripts/
cat ~/.claude/settings.jsonStep 7: Test Timing Data Collection
IMPORTANT: After installation, verify that timing data is being collected correctly by running a skill and checking the logs.
1. Run any skill (e.g., a simple one like glossary-generator) 2. Check that the skill-usage.jsonl contains timing data:
tail -5 ~/.claude/activity-logs/skill-usage.jsonl3. Run the analysis report to verify timing appears:
bk-analyze-skill-usageLook for these timing metrics in the report:
- Time from Prompt column in Recent Skill Usage table
- Avg Time column in Token Usage by Skill table
- Timing Summary section with total and average time
If timing shows "N/A" or "0s", see the Troubleshooting section below.
Using the Tracking System
Automatic Logging
After installation, the tracking system operates automatically across all projects: 1. Use skills normally through Claude Code in any project 2. Each skill invocation is logged with timestamp, duration, token usage, and triggering prompt 3. Logs accumulate in ~/.claude/activity-logs/ as JSONL files (centralized for all projects)
What Gets Tracked (v2.1):
- Skill name and invocation time
- Timing metrics:
- Time from prompt submission to skill completion
- Duration between start and end events
- Session activity timeline (time between prompts)
- Token usage metrics:
- Input tokens (new content)
- Output tokens (generated response)
- Cache read tokens (from prompt cache)
- Cache creation tokens (creating cache entries)
- Total tokens (sum of all above)
- User prompt that triggered the skill
- Session ID for correlation
- Project directory (for filtering by project if needed)
Analyzing Usage Data
Run the analysis scripts to generate insights:
Pattern and Performance Analysis:
~/.claude/scripts/analyze-skills.pyToken Usage and Cost Analysis (v1.2):
~/.claude/scripts/show-skill-tokens.shThe analysis reports include:
- Skill frequency - Most commonly used skills
- Timing metrics - Time from prompt to completion, average time per skill
- Timing summary - Total time spent in skills, average time per skill
- Session activity timeline - Time gaps between prompts to understand work patterns
- Token usage metrics - Input/output/cache tokens per skill
- Cost estimation - Calculate API costs based on token usage
- Cache efficiency - Identify cache hit rates and optimization opportunities
- Prompt patterns - Common prompts that trigger skills
- Usage history - Recent skill invocations with timing and token details
- Insights - Suggestions for optimization and new skill opportunities
Example Analysis Output
# Skill Usage Analysis Report
**Total skill invocations:** 15
## Token Usage by Skill
| Skill | Invocations | Total Tokens | Avg Time | Cache Read | Cache Creation |
|-------|-------------|--------------|----------|------------|----------------|
| learning-graph-generator | 5x | 420.5K | 2m 34s | 380.2K | 15.3K |
| microsim-p5 | 7x | 168.7K | 1m 12s | 145.6K | 8.1K |
| glossary-generator | 3x | 45.2K | 45s | 38.9K | 2.4K |
## Timing Summary
| Metric | Value |
|--------|-------|
| Total time in skills | 45m 23s |
| Average time per skill | 3m 1s |
| Skills with timing data | 15 of 15 |
## Recent Skill Usage
| Timestamp | Skill | Tokens | Time from Prompt | Prompt (truncated) |
|-----------|-------|--------|------------------|---------------------|
| 2025-12-03 14:25:33 | microsim-p5 | 24.1K | 1m 15s | create a bubble chart microsim... |
| 2025-12-03 14:12:41 | glossary-generator | 15.1K | 42s | generate glossary from learning... |
## Session Activity Timeline
| Timestamp | Time Since Previous | Prompt (truncated) |
|-----------|---------------------|---------------------|
| 2025-12-03 14:25:33 | 12m 52s | create a bubble chart microsim... |
| 2025-12-03 14:12:41 | 3m 15s | generate glossary from learning... |
## Insights
### Most Token-Intensive Skills
- **learning-graph-generator**: 420.5K total (84.1K avg)
### Cache Efficiency
✅ Good cache utilization (89.2% cache hits)Log Data Format
The system creates two JSONL log files in ~/.claude/activity-logs/:
prompts.jsonl
Logs user prompts with session correlation:
{"timestamp": "2025-11-22 14:23:45", "epoch": "1732299825", "session": "abc123", "project": "/path/to/project", "prompt": "create a learning graph"}skill-usage.jsonl
Logs skill start/end events with duration and token usage:
{"timestamp": "2025-11-22 14:23:46", "epoch": "1732299826", "session": "abc123", "project": "/path/to/project", "skill": "learning-graph-generator", "event": "start"}
{"timestamp": "2025-11-22 14:26:20", "epoch": "1732299980", "session": "abc123", "project": "/path/to/project", "skill": "learning-graph-generator", "event": "end", "duration_seconds": "154", "input_tokens": 12000, "output_tokens": 8500, "total_tokens": 84200, "cache_read_tokens": 62400, "cache_creation_tokens": 1300}Customization Options
Tracking Additional Metrics
Extend the hook scripts to capture:
- All tool usage (not just skills)
- Error rates and failures
- Custom metadata fields
- Project-specific context
Hooks receive full JSON context via stdin with tool names, parameters, and outputs.
Privacy & Security
All tracking data is stored locally:
- No data transmission to external services
- Logs remain in
~/.claude/activity-logs/ - Stored in your home directory, not in project directories
To delete all tracking data:
rm -rf ~/.claude/activity-logsTroubleshooting
JSON Parsing Errors
IMPORTANT FIX (v1.1): The hook scripts now use jq -nc instead of jq -n to generate compact JSON output. This is critical for proper JSONL format.
If you encounter errors like:
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotesYour existing log files may have pretty-printed JSON. Fix with:
jq -c '.' ~/.claude/activity-logs/prompts.jsonl > temp && mv temp ~/.claude/activity-logs/prompts.jsonl
jq -c '.' ~/.claude/activity-logs/skill-usage.jsonl > temp && mv temp ~/.claude/activity-logs/skill-usage.jsonlHooks Not Executing
Verify hook configuration:
cat ~/.claude/settings.jsonCheck script permissions:
ls -l ~/.claude/hooks/*.shNo Log Files Created
Ensure directories exist:
mkdir -p ~/.claude/activity-logsUse a skill to trigger logging, then check:
ls -la ~/.claude/activity-logs/Analysis Shows No Data
Logs are created only after skill usage. Run any skill first, then execute the analysis script.
Detailed Troubleshooting
For comprehensive troubleshooting, see the README.md in this skill directory, which includes:
- JSONL format requirements and the
-cflag fix - Common issues and solutions
- Hook debugging techniques
- Custom analysis queries
Resources
This skill includes:
scripts/
- track-prompts.sh - Bash hook to log user prompts
- track-skill-start.sh - Bash hook to log skill start times
- track-skill-end.sh - Bash hook to log skill completion, duration, and tokens (v1.2)
- analyze-skills.py - Python script to analyze logs and generate reports
- show-skill-tokens.sh - Bash script to display token usage and cost metrics (v1.2)
assets/
- settings.json - Hook configuration template for
.claude/settings.json - README.md - Complete documentation for the tracking system