Step-by-step installation and configuration for Socratic Study Mentor.
- Prerequisites
- Installation
- Configuration
- Obsidian Vault Setup
- NotebookLM Setup
- Session Database
- Content Pipeline
- Cross-Machine Sync
- Scheduling
- Troubleshooting
- Python 3.12+ (both studyctl and agent-session-tools require 3.12+)
- uv — Python package manager
- Obsidian — for study notes (any vault structure works)
- Optional:
notebooklm-pyfor Google NotebookLM sync - Optional:
sentence-transformersfor semantic search
git clone https://github.com/NetDevAutomate/Socratic-Study-Mentor.git
cd socratic-study-mentor
./scripts/install.shThis will:
- Verify Python 3.12+ is installed
- Install
uvif not already available - Run
uv syncto install both packages - Run
install-agents.shto set up AI agent definitions - Create a default config at
~/.config/studyctl/config.yaml - Optionally download the kokoro-onnx voice model (~85MB) for TTS support
git clone https://github.com/NetDevAutomate/Socratic-Study-Mentor.git
cd Socratic-Study-Mentor
# Full install (interactive — prompts for TTS voice model)
./scripts/install.sh
# Full install without prompts (for Ansible/CI)
./scripts/install.sh --non-interactive
# Just reinstall/upgrade CLI tools globally
./scripts/install.sh --tools-only
# Just reinstall agent definitions
./scripts/install.sh --agents-only
# Install optional extras
uv pip install studyctl[notebooklm]
uv pip install agent-session-tools[semantic]For Ansible playbooks, clone the repo then run the install script:
- name: Install Socratic Study Mentor
hosts: study_machines
tasks:
- name: Clone repo
git:
repo: https://github.com/NetDevAutomate/Socratic-Study-Mentor.git
dest: ~/code/personal/tools/Socratic-Study-Mentor
- name: Run installer
command: ./scripts/install.sh --non-interactive
args:
chdir: ~/code/personal/tools/Socratic-Study-MentorRun the interactive wizard to configure your study environment:
studyctl config initThis walks you through three core questions:
- Knowledge bridging — Do you want to leverage a topic you already know well (e.g. networking, cooking, music theory) so the mentor can draw analogies to new topics you're studying?
- NotebookLM integration — Do you want to integrate with Google's NotebookLM to use notebooks as a knowledge source?
- Obsidian vault — Do you want to integrate with an existing Obsidian vault? If so, provide the base path (e.g.
~/Obsidian/Vault).
The wizard creates or updates ~/.config/studyctl/config.yaml with your choices. You can re-run it at any time to change settings.
All configuration lives in a single file: ~/.config/studyctl/config.yaml. This file is shared between studyctl and all session-* tools — use the same file on every machine.
The study web app requires no extra dependencies — just run:
studyctl webThis starts a web server on http://0.0.0.0:8567 accessible from any device on your network. Open it on your phone, tablet, or laptop.
Install as PWA (iOS/Android): Open in Safari → Share → Add to Home Screen. The app then works full-screen like a native app.
Configure flashcard/quiz directories:
# ~/.config/studyctl/config.yaml
review:
directories:
- ~/Desktop/ZTM-DE/downloads
- ~/Desktop/Python/downloadsVoice output uses the Web Speech API (built into all browsers). For best quality voices:
- macOS: System Settings → Accessibility → Spoken Content → System Voice → Manage Voices → download Samantha (Enhanced) or Ava (Premium)
- iOS: Settings → Accessibility → Spoken Content → Voices → English → download Siri voices
- Windows: Settings → Time & Language → Speech → Manage voices
Two voice modes in the PWA:
- Read once — tap the speaker icon on a card, or press
T. Reads the current content once. - Auto-voice — toggle the header speaker icon, or press
V. Reads everything automatically as you navigate.
Accessibility: The Aa button toggles OpenDyslexic font. The sun icon toggles light/dark theme. Both are persisted across sessions.
The terminal TUI requires the [tui] extra:
uv pip install studyctl[tui]
studyctl tuiOptional TUI settings:
# ~/.config/studyctl/config.yaml
tui:
theme: dracula # Any Textual theme (dracula, nord, tokyo-night, etc.)
dyslexic_friendly: true # Wider spacing, more padding (also toggle with o key)Voice output in the TUI requires the [tts] extra on agent-session-tools:
uv tool install "./packages/agent-session-tools[tts]"Dyslexic-friendly mode in the terminal — for best results, set your terminal font to OpenDyslexic:
- iTerm2: Preferences → Profiles → Text → Font → select OpenDyslexic
- Terminal.app: Preferences → Profiles → Font → Change → select OpenDyslexic
- Windows Terminal: Settings → Profiles → Appearance → Font face → OpenDyslexic
- VS Code terminal:
"terminal.integrated.fontFamily": "OpenDyslexic"
Cross-machine sync uses SSH and rsync under the hood. Passwordless SSH must be configured between all machines before sync will work. If you're prompted for a password, sync will hang or fail.
Set up SSH key-based auth between each pair of machines:
# 1. Generate a key (if you don't have one)
ssh-keygen -t ed25519 -C "your-email@example.com"
# 2. Copy your public key to each remote machine
ssh-copy-id ataylor@192.168.125.22 # macmini
ssh-copy-id ataylor@192.168.125.21 # macbookpro
# 3. Verify passwordless login works
ssh ataylor@192.168.125.22 "echo ok" # should print "ok" with no password promptDo this from every machine to every other machine you want to sync with. If machine A syncs with B and C, then A needs key access to B and C, B needs access to A and C, etc.
Platform limitation: Cross-machine sync requires a native Unix/Linux SSH server on the remote host with direct access to the filesystem. This means sync does not work with:
- Windows hosts running WSL — SSH connects to Windows, not the WSL filesystem where the database lives. The
$HOMEpath andsqlite3binary won't resolve correctly.- Docker containers — unless SSH is exposed from the container (not recommended). The database path inside the container differs from the host path.
- Network-attached storage — the remote needs
sqlite3installed and SSH access.Supported targets: macOS, native Linux, any Unix system with SSH + sqlite3.
The hosts section defines all your machines. The local machine is auto-detected by matching your system hostname, and everything else becomes a sync target.
hosts:
macmini:
hostname: Andys-Mac-Mini # must match socket.gethostname()
ip_address:
primary: 192.168.125.22 # wired / ethernet
secondary: 192.168.125.12 # wifi (optional fallback)
user: ataylor
state_json: ~/.config/studyctl/state.json
sessions_db: ~/.config/studyctl/sessions.db
macbookpro:
hostname: Andys-MacBook-Pro-Max
ip_address:
primary: 192.168.125.21
user: ataylor
state_json: ~/.config/studyctl/state.json
sessions_db: ~/.config/studyctl/sessions.db
work-macbook:
hostname: 842f575e3614
ip_address:
primary: 192.168.125.20
user: taylaand
state_json: ~/.config/studyctl/state.json
sessions_db: ~/.config/studyctl/sessions.dbOne config file on all machines. Deploy the same config.yaml everywhere — each machine auto-detects itself by hostname and treats the rest as remotes.
| Field | Description |
|---|---|
hostname |
Must match socket.gethostname() on that machine |
ip_address.primary |
Wired/ethernet IP (tried first for rsync/SSH) |
ip_address.secondary |
Wifi IP (optional fallback if primary unreachable) |
user |
SSH username for this machine |
state_json |
Path to studyctl state file |
sessions_db |
Path to the AI session SQLite database |
Both studyctl state push/pull and session-sync push/pull/sync use this config:
# studyctl
studyctl state push macmini
studyctl state pull macbookpro
studyctl state status
# session-sync (same host names, same config)
session-sync push macmini
session-sync pull macbookpro
session-sync sync work-macbook
session-sync endpoints # list all remote hoststopics:
- name: Python
slug: python
obsidian_path: 2-Areas/Study/Python
# notebook_id: your-notebooklm-notebook-id # optional
tags: [python, programming]
- name: SQL
slug: sql
obsidian_path: 2-Areas/Study/SQL
tags: [sql, databases]| Field | Description | Default |
|---|---|---|
topics[].name |
Display name for the topic | required |
topics[].slug |
URL-safe identifier | required |
topics[].obsidian_path |
Path relative to obsidian_base |
required |
topics[].notebook_id |
NotebookLM notebook ID (if using sync) | empty |
topics[].tags |
Keywords for session search matching | [] |
database:
path: ~/.config/studyctl/sessions.db
archive_path: ~/.config/studyctl/sessions_archive.db
backup_dir: ~/.config/studyctl/backups
thresholds:
warning_mb: 100
critical_mb: 500
semantic_search:
model: all-mpnet-base-v2 # embedding model
fts_weight: 0.4 # hybrid search: FTS weight
semantic_weight: 0.6 # hybrid search: vector weight
min_content_length: 50
auto_embed: trueEnvironment variable overrides:
DATABASE_PATH— override database locationLOG_LEVEL— set logging level (DEBUG, INFO, WARNING, ERROR)EMBEDDING_MODEL— override embedding model
tts:
voice: am_michael # kokoro voice (am_michael, af_heart, bf_emma, etc.)
speed: 1.5 # 0.5 = slow, 1.0 = normal, 1.5 = fast
pause: 0.0 # seconds between sentences
backend: kokoro # kokoro | qwen3 | macosstudyctl expects your study notes in directories under your Obsidian vault. The structure is flexible — just point each topic's obsidian_path at the right directory.
Example vault layout:
~/Obsidian/
├── Personal/
│ └── 2-Areas/
│ └── Study/
│ ├── Courses/
│ │ ├── ArjanCodes/ ← Python topic
│ │ └── DataCamp/ ← SQL topic
│ ├── Mentoring/
│ │ ├── Python/ ← AI-generated teaching moments
│ │ ├── Databases/
│ │ └── Data-Engineering/
│ └── Study-Plans/
studyctl syncs .md, .pdf, and .txt files. It skips:
- Files under 100 bytes
- Obsidian metadata files (
.obsidian/, index files) - Common non-content directories (
node_modules,__pycache__)
NotebookLM sync lets you upload your Obsidian notes as sources in Google NotebookLM notebooks, then generate audio overviews.
-
Install the optional dependency:
uv pip install studyctl[notebooklm]
-
Create notebooks in NotebookLM — one per study topic
-
Get each notebook's ID from its URL:
https://notebooklm.google.com/notebook/NOTEBOOK_ID_HERE -
Add the IDs to your config:
topics: - name: Python slug: python obsidian_path: 2-Areas/Study/Python notebook_id: your-notebook-id-here
-
Sync and generate audio:
studyctl sync python # Upload changed notes studyctl audio python # Generate audio overview
The session database stores exported AI conversations from all your tools. It powers spaced repetition, struggle detection, and session search.
# Export from all detected sources
session-export
# Export from a specific source
session-export --source claude
session-export --source kiro
session-export --source aiderSupported sources: claude, kiro, gemini, opencode, aider, litellm, repoprompt
session-query stats # Show database statistics
session-query list --since 7d # List recent sessions
session-query search "python" # Search across all sessionsThe content pipeline converts PDFs and Obsidian notes into NotebookLM-powered study materials (audio overviews, flashcards, quizzes). It was absorbed from notebooklm-pdf-by-chapters and lives under studyctl content.
# PDF splitting (pymupdf + httpx)
uv pip install studyctl[content]
# NotebookLM integration (required for upload/generate/download commands)
uv pip install studyctl[notebooklm]Point studyctl at the directories where content pipeline outputs land (flashcards, quizzes). These are picked up by studyctl review, the web PWA, and the TUI:
# ~/.config/studyctl/config.yaml
review:
directories:
- ~/Desktop/ZTM-DE/downloads
- ~/Desktop/Python/downloads# 1. Split a PDF textbook into per-chapter files
studyctl content split ~/Books/my-textbook.pdf -o ./chapters
# 2. Upload chapters to NotebookLM and generate audio overviews
studyctl content process ~/Books/my-textbook.pdf -n NOTEBOOK_ID
# 3. Or use the syllabus workflow for multi-episode podcast generation
studyctl content syllabus -n NOTEBOOK_ID -o ./chapters
studyctl content autopilot -o ./chapters
# 4. Convert Obsidian notes to PDFs and upload in one step
studyctl content from-obsidian ~/Obsidian/Vault/Study/PythonSee the CLI Reference for all available commands.
Both tools support syncing state across machines via SSH.
studyctl state push macmini # Push local state to a named host
studyctl state pull macbookpro # Pull state from a named host
studyctl state status # Check connectivity to all hosts
studyctl state init # Initialize sync configsession-sync push macmini # Push sessions to a named host
session-sync pull macbookpro # Pull sessions from a named host
session-sync sync work-macbook # Two-way sync with a host
session-sync endpoints # List all configured remote hostsBoth commands read host definitions from ~/.config/studyctl/config.yaml (the hosts section). See the Hosts configuration in the README for the full schema. Delta sync transfers only new sessions, not the entire database.
Set up automatic sync so your notes and sessions stay current.
# Install all default scheduled jobs
studyctl schedule install
# List active jobs
studyctl schedule list
# Remove all jobs
studyctl schedule remove
# Add a custom job
studyctl schedule add my-sync "studyctl sync --all" "daily 3am"On macOS, this creates launchd plists. On Linux, it uses cron.
The toolkit runs on Windows via WSL2 (Windows Subsystem for Linux).
- Install WSL2 with Ubuntu:
wsl --install -d Ubuntu - Inside WSL2, install Python 3.12+ and uv:
curl -LsSf https://astral.sh/uv/install.sh | sh - Clone and install as normal (all commands run inside WSL2)
- All CLI tools (
studyctl,session-export,session-query, etc.) - kiro-cli and Claude Code (terminal-based)
- SQLite database, FTS5 search, session sync
- Cron scheduling (enable with
sudo service cron startor systemd) - Git, pre-commit, ruff, pyright, pytest
| Feature | macOS | WSL2 |
|---|---|---|
| Scheduling | launchd (automatic) | cron (enable manually) |
| Calendar MCP | Apple Calendar or Google | Google Calendar only |
| Reminders | Apple Reminders (native notifications) | Google Calendar reminders |
| Obsidian vault | ~/Obsidian/ |
/mnt/c/Users/<name>/Obsidian/ |
| PDF rendering | brew install pandoc mactex |
sudo apt install pandoc texlive-xetex |
| Claude Desktop | Native app | Runs on Windows side |
Claude Desktop runs on Windows but can connect to MCP servers inside WSL2:
{
"mcpServers": {
"study-tools": {
"command": "wsl",
"args": ["--", "npx", "-y", "your-mcp-server"]
}
}
}If your Obsidian vault is on the Windows filesystem, configure the path in ~/.config/studyctl/config.yaml:
obsidian_base: /mnt/c/Users/YourName/ObsidianFor better performance, consider keeping the vault inside WSL2's native filesystem (~/Obsidian/) and syncing with Obsidian Sync or Git.
After installing and configuring, run the health check to make sure everything is working:
studyctl doctorThis checks Python version, installed packages, config validity, databases, optional dependencies, and AI agent definitions. You'll see a colour-coded table:
- Green tick = healthy
- Yellow ! = warning (often auto-fixable)
- Red cross = failure (needs attention)
- Blue i = informational (optional)
If issues are found:
studyctl upgrade # Fix auto-fixable issues (packages, DB, agents)
studyctl upgrade --dry-run # Preview changes firstFor machine-readable output (used by CI pipelines and AI agents):
studyctl doctor --jsonIf you're using an AI coding assistant, the install-mentor agent can guide you through the entire setup process conversationally. It automatically detects your environment, installs packages, runs studyctl doctor, and fixes issues.
The prompt lives at agents/shared/install-mentor.md and works with any AI tool that can run shell commands — Claude Code, Kiro CLI, Gemini CLI, OpenCode, or Amp.
To use it in Claude Code:
Read agents/shared/install-mentor.md and follow its instructions to set up studyctl
Before investigating specific issues, always start with the health check:
studyctl doctorThis will identify most common problems and tell you how to fix them. If auto-fixable issues are found, run studyctl upgrade to resolve them.
The package isn't on your PATH. Either:
- Run via
uv run studyctlinstead - Or ensure
uv synccompleted successfully and your shell can find uv-installed scripts
Check that the AI tool's data directory exists:
- Claude Code:
~/.claude/projects/ - Kiro CLI:
~/Library/Application Support/kiro-cli/data.sqlite3(macOS) - Gemini CLI:
~/.gemini/tmp/ - Aider:
.aider.chat.history.mdfiles in project directories
The session database may be empty. Run session-export first to populate it, then studyctl review can check your study history.
- Verify
notebooklm-pyis installed:uv pip install studyctl[notebooklm] - Check that your
notebook_idis correct (copy from the NotebookLM URL) - Ensure you're authenticated with Google (follow
notebooklm-pyauth docs)
studyctl looks for config at ~/.config/studyctl/config.yaml. Override with:
export STUDYCTL_CONFIG=/path/to/your/config.yamlsession-maint vacuum # Reclaim space
session-query stats # Check current size
session-maint archive # Archive old sessions