Personal Active Learning & Evaluation Engine
A deterministic, Spaced-Repetition (SM-2) & Directed Acyclic Graph (DAG) study engine for Obsidian vaults.
Complete interactive documentation with architecture guides, interactive Mermaid diagrams, and CLI command references is available at https://kuldeep2822k.github.io/cli/.
PALEE helps you learn efficiently by:
- Recommending what to study next based on dependencies and SM-2 scheduling
- Tracking mastery across conceptual, practical, debug, and teaching dimensions
- Scheduling reviews using scientifically-proven spaced repetition
- Integrating natively with Obsidian notes
- Providing AI-powered Feynman testing
- Remembering learning context between sessions through durable session logs and a compact hot-memory file
npm install -g @kuldeep2822k/paleeRequires Node >=22.12.0 (the package's engines floor).
Upgrade later with palee update (--dry-run reports current and latest without installing).
palee update opens no network connection itself — it delegates to your own npm, with the user
and global .npmrc you already have.
On an interactive terminal a newer release is also announced at most once per 24 hours with a single ⚠
line on stderr; set PALEE_NO_UPDATE_CHECK=1 to silence it.
palee config set-vault ~/Documents/Obsidian/Learningpalee config set-provider opencode
palee config set-base-url https://opencode.ai/zen/v1
printf '%s' "$OPENCODE_API_KEY" | palee config set-api-key
palee config set-model nemotron-3-ultra-free
palee config test-connectionset-api-key takes the key on stdin, via --from-env <VAR>, or as an interactive prompt — never as an
argument, because argv is readable by every other process. palee config show never prints it; the key
is stored in the config file, written 0600 on POSIX. On Windows that mode is ignored, so set-api-key
instead refuses to store the key when the config directory is outside your user profile (see Windows Notes).
PALEE_API_KEY in the environment outranks the stored key, for anyone who would rather never write it to disk.
Changing the base URL to a different origin while a key is stored asks for confirmation on a terminal; pass
--keep-key to skip the prompt. A non-interactive or --json run refuses without that flag, so run
palee config unset-api-key first if the stored key should not follow the new endpoint.
test-connection sends one short prompt and reports the URL it called, which key source won, how long
the reply took and how many tokens it cost. It is the only command that reaches the network, and nothing
in palee next, palee plan, palee review, palee validate, palee adopt, palee roadmap --from or palee migrate can do the same —
test/ai-network-boundary.test.ts fails if a second socket site appears. It refuses plain HTTP to any
host that is not loopback, refuses endpoints in reserved address space (link-local and the cloud metadata
address, the unspecified and multicast ranges, IPv4-mapped literals, and .internal names), refuses
redirects rather than re-sending the credential to a host nobody approved, reads no more than 256 KiB of a
response before giving up on it, and exits 2 on a bad endpoint, 3 on a reply that broke the output
contract, 5 when the provider could not be reached.
# See what to study next
palee next
# Build a study session
palee plan
# Track your progress
palee progress- Dependency-aware: Never study topics before prerequisites
- Spaced repetition: Reviews scheduled using SM-2 algorithm
- Unlock-based scoring: Topics scored by how many they unlock
- Native vault support: Works directly with your existing notes
- Frontmatter metadata: Study data stored in note frontmatter
- Zero duplication: Vault IS the data store
- Feynman method: AI tests your ability to explain concepts
- Multi-dimensional grading: Conceptual, practical, debug, teaching scores
- Tool-constrained: AI receives read-only validated context tools; PALEE owns confirmed writes
Neither palee test nor palee tutor is implemented yet, so the commands below do not
run. The four-pillar scores they would write are already stored and read by
palee assess and palee review today.
- Mastery visualization: Track mastery across all topics
- Review scheduling: Never miss a review
- Track analytics: See your learning patterns
- Durable session logs: Every confirmed session is saved as a searchable Obsidian note
- Hot memory: The next session starts with a concise summary of the current learning position
- Stable references: Topics, sessions, and durable decisions use immutable IDs
# 1. Adopt your existing notes
palee adopt "Docker Fundamentals.md"
# 2. See what to learn next
palee next
# → Learn: Pod Lifecycle in Kubernetes
# 3. Record a review after studying it
palee review T-pod-lifecycle-k8s 4
# → SM-2 reschedules the next review date
# 4. Track progress
palee progress
# → 23.45% overall mastery| Command | Description |
|---|---|
palee next |
Show next recommended action |
palee plan |
Build study session plan |
palee progress |
View mastery statistics |
palee review <topic> <quality> |
Record review result (0-5) |
palee assess <topic> |
Record a four-pillar assessment (conceptual, practical, debug, Feynman) and recompute mastery |
palee session start |
Resume learning from hot memory; starts AI tutor if provider is configured |
palee session end |
Save a confirmed session summary and refresh hot memory |
palee session draft |
Save a recoverable draft checkpoint for the active session |
palee session list |
List session history and pending drafts |
palee migrate |
Upgrade versioned PALEE data safely |
palee adopt <note> |
Adopt Obsidian note into PALEE |
palee roadmap --from <file> |
Validate and import a user-provided roadmap (no AI, no network) |
palee dashboard |
Show system status |
palee validate |
Check data integrity |
palee config set-vault <path> |
Set the Obsidian vault path |
palee config set-provider <name> |
Name the AI provider |
palee config set-base-url <url> |
Set the OpenAI-compatible endpoint (http / https only); a changed origin with a stored key needs confirmation or --keep-key |
palee config set-api-key |
Store the provider key from stdin, --from-env <VAR>, or a prompt |
palee config unset-api-key |
Remove the stored key |
palee config set-model <model> |
Set the model identifier |
palee config test-connection |
Send one short prompt to verify the provider (the only command that talks to a network endpoint directly; palee update delegates to npm) |
palee config show |
Display current config — vault path, provider, endpoint, model; the key prints as •••••••• |
palee update [--dry-run] |
Update the global install through npm, or report what would change |
Phase 2 will add palee test and palee tutor, and a palee roadmap interview mode.
None of the three is implemented: palee test and palee tutor are not registered commands,
and palee roadmap without --from exits 2 rather than starting an interview.
Flags that change what a command does, rather than which rows it prints:
| Option | Description |
|---|---|
palee adopt <path> --undo |
Reverse an adoption: strip only the PALEE-owned frontmatter keys, preserving every other key, comment and body byte |
palee adopt <path> --undo --drop-title |
With --undo: also remove the title key |
palee adopt <path> --auto-chain |
Wire depends_on from a note's own prerequisites, else the numbered tree (batch mode; Tier-0 hygiene is on for every batch, so this flag wires rather than filters — except that a chained scan keeps README/SUMMARY as chain backbone, which a plain scan skips) |
palee adopt <path> --auto-chain --chain-tier <tier> |
strict (default) consumes numbers only; full adds listing order, which never gates |
palee adopt <path> --dry-run |
Preview an adoption without writing — likewise palee roadmap and palee migrate |
palee validate --fix |
Repair corrupted SM-2 review fields to adopt defaults |
palee migrate --fix |
Upgrade notes missing palee_schema to schema v1 |
palee migrate --relabel-ties |
Store an alphabetical tiebreak as tie rather than numbered, so ties stop gating; depends_on is never changed |
palee migrate --relabel-ties --include-unlabeled-ties |
Also relabel ties with no depends_on_source key at all (opt-in; combine with --dry-run to preview) |
palee roadmap --from <file> --auto-chain |
Chain imported topics in order (ascending order field; unordered notes follow in file order) |
palee config set-provider opencode
palee config set-base-url https://opencode.ai/zen/v1
palee config set-api-key --from-env OPENCODE_API_KEY
# Supports any OpenAI-compatible endpoint
# Recommended free option: OpenCode ZenThe key is kept in the config file, stored as plaintext at rest under a 0600 mode on POSIX, and no
command prints it. On Windows the file mode does not apply, so the key's privacy rests on the config
directory's ACL; see Windows Notes for how set-api-key guards that. palee roadmap --from <file> and every offline
command work without any of this.
palee config set-vault /path/to/obsidian/vault
# PALEE will scan for notes with frontmatterEach topic note stores flat YAML frontmatter directly inside your Obsidian vault:
---
palee_schema: 1
palee_id: T-docker-volumes
title: Docker Volumes
difficulty: beginner
depends_on:
- T-docker-basics
topic_mastery: 0.725
conceptual: 0.85
practical: 0.70
debug: 0.60
feynman: 0.75
assessed_at: 2026-01-15
ease_factor: 2.36
interval_days: 6
repetition: 1
lapses: 0
last_quality: 4
last_reviewed_at: 2026-01-15
due_at: 2026-01-21
---Frontmatter stores flat keys directly for clean Obsidian parsing and fast atomic updates. Programmatic TypeScript interfaces (Topic) map these fields into structured conceptual and review metrics.
topic_mastery is derived from assessment scores ((conceptual + practical + debug + 2*feynman) / 5), independent from SM-2 recall scheduling. Newly adopted notes begin with topic_mastery: 0.0 and null review fields.
Session memory is stored inside the connected vault:
.palee/
├── hot.md
├── sessions/
└── index.md
hot.md is capped at 250 words and points to the latest full session. Full session notes preserve the learning history without forcing every future AI prompt to load the entire log.
See memory_design.md for the session-memory format, lifecycle, stable IDs, and recovery rules.
See storage_design.md for frontmatter preservation, atomic writes, vault traversal, validation, and cache behavior.
See invariants.md for the acceptance-test blueprint that must pass before Phase 1 is considered complete.
See roadmap_design.md for the imported-roadmap and guided personalized-roadmap contracts.
PALEE is built on three principles:
- Deterministic core: Reliable SM-2 scheduling and dependency tracking
- AI augmentation: Intelligent tutoring constrained to validated actions
- Human oversight: You confirm all consequential actions
PALEE uses standard exit codes to facilitate scripting:
0: Success1: Partial failure (e.g., batch roadmap import where some topics failed)2: Usage error or configuration refusal (e.g., missing argument, unconfigured vault, aset-base-urlconfirmation invalidated by a concurrent config change)3: Validation error (e.g., malformed roadmap, invalid dependency)4: Optimistic concurrency conflict during a file write (file was modified by another process)5: Unexpected error (e.g., Node.js exception)
Commands emit human-readable terminal output by default (even when piped). Pass --json or set PALEE_JSON=1 to emit structured JSON for scripts and automated workflows (--json is declared on config, next, plan, progress, validate, session and dashboard; the remaining commands are human-only):
palee plan --json | jq '.ready_to_learn[]'
PALEE_JSON=1 palee next | jq -r '.next.path'- Path Normalization: PALEE natively handles both forward slashes (
/) and backslashes (\) for vault configuration and file references. - Lock Timeouts: On Windows, file locks become stale after 60 seconds (vs 120s on Unix) to accommodate aggressive process termination without
finallyblocks executing. - Config Storage: The config file on Windows is stored in
%LOCALAPPDATA%\palee\config.json. - API key privacy: Because Windows ignores the POSIX
0600file mode and resolves access through the directory's inherited ACL,palee config set-api-keyrefuses to write the key when the config directory resolves outside your user profile (%USERPROFILE%/%LOCALAPPDATA%) — a share or synced folder can grant other principals read access. The refusal names the directory. To proceed anyway, pass the key at runtime via thePALEE_API_KEYenvironment variable (never written to disk), movePALEE_CONFIG_DIRunder your profile, or setPALEE_ALLOW_INSECURE_CONFIG_DIR=1if you have secured the directory by other means.
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
Detailed contribution guidelines will be added with the implementation source.
MIT (see LICENSE).
