ari-review
Run spaced repetition reviews (SM-2) with retrieval-first prompts and quality scoring
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Run spaced repetition reviews (SM-2) with retrieval-first prompts and quality scoring
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Discord slash commands, approval routing, channel policy, button interaction patterns for OpenClaw/ARI Discord integration
Obsidian vault integration patterns — vault-analyzer.ts, /ari-vault-* commands, morning briefing snippet, PARA structure, read-only enforcement
OpenClaw plugin development patterns — hooks, manifest structure, plugin SDK, APEX/CODEX enforcement
NOVA's P1 PayThePryce pipeline — market signal ingest, card detection, price monitoring, script generation, thumbnail generation, video assembly, approval gate
CHASE's P2 Pryceless Solutions pipeline — lead discovery, 5-criteria audit, LLM qualification, Prompt Forge 4-pass lock, demo generation, outreach approval gate
NOVA's thumbnail generation pipeline — Ideogram V3 via Fal.ai (primary) + DALL-E 3 fallback, 4-variant strategy, Pokemon TCG copyright rules,
| name | ari-review |
| description | Run spaced repetition reviews (SM-2) with retrieval-first prompts and quality scoring |
| triggers | ["daily review","spaced repetition","review due","SM-2","quiz me","/ari-review"] |
Run a spaced repetition review session using the SM-2 algorithm. This implements evidence-based learning science from Roediger & Karpicke (2006) showing retrieval practice produces 3x better retention than restudying.
When invoked, execute this review session:
// 1. Initialize the spaced repetition engine (loads from ~/.ari/learning/)
const { getSpacedRepetitionEngine } = await import('../cognition/learning/spaced-repetition.js');
const engine = await getSpacedRepetitionEngine();
// 2. Get cards due for review
const now = new Date();
const dueCards = engine.getReviewsDue(now);
const stats = engine.getStats();
For each due card, present this interaction:
┌─────────────────────────────────────────────────────────────┐
│ 📚 ARI REVIEW SESSION │
│ Card 1/5 • 5 cards due for review │
├─────────────────────────────────────────────────────────────┤
│ │
│ CONCEPT: Expected Value │
│ │
│ Q: What is the formula for Expected Value? │
│ │
│ [Take a moment to recall before revealing the answer...] │
│ │
├─────────────────────────────────────────────────────────────┤
│ [Press Enter to reveal answer] │
└─────────────────────────────────────────────────────────────┘
After user attempts recall, reveal and rate:
┌─────────────────────────────────────────────────────────────┐
│ ANSWER REVEALED │
├─────────────────────────────────────────────────────────────┤
│ │
│ A: EV = Σ(probability × value) │
│ │
│ How well did you recall this? │
│ │
│ [0] Complete blackout │
│ [1] Incorrect; barely remembered │
│ [2] Incorrect; remembered fragments │
│ [3] Correct with serious difficulty │
│ [4] Correct with minor hesitation │
│ [5] Perfect recall; effortless │
│ │
└─────────────────────────────────────────────────────────────┘
// After user provides quality rating (0-5)
const review = await engine.reviewCard(card.id, quality);
// Show feedback
console.log(`
✅ Card updated!
Ease Factor: ${card.easeFactor.toFixed(2)} → ${review.easeFactorAfter.toFixed(2)}
Next Review: ${review.nextReview.toLocaleDateString()} (${review.intervalAfter} days)
`);
At the end of the session:
═══════════════════════════════════════════════════════════════
📊 SESSION COMPLETE
═══════════════════════════════════════════════════════════════
Cards Reviewed: 5
✅ Perfect (5): 2
✅ Good (4): 1
⚠️ Hard (3): 1
❌ Failed (0-2): 1
Average Quality: 3.6/5
Time Spent: 4 minutes
📈 Statistics:
Total Cards: 47
Due Tomorrow: 8
Average Ease: 2.43
Reviewed Today: 12
Next review session: Tomorrow at 8:00 AM
═══════════════════════════════════════════════════════════════
| Quality | Meaning | Effect |
|---|---|---|
| 5 | Perfect recall | Interval × ease factor |
| 4 | Correct with hesitation | Interval × ease factor |
| 3 | Correct with difficulty | Interval × ease factor |
| 2 | Wrong but easy in hindsight | Reset to 1 day |
| 1 | Wrong, barely remembered | Reset to 1 day |
| 0 | Complete blackout | Reset to 1 day, decrease ease |
If the user wants to add concepts to review:
const card = await engine.createCard({
concept: 'Kelly Criterion',
front: 'What is the Kelly Criterion formula?',
back: 'f* = (bp - q) / b, where b = odds, p = win probability, q = 1-p',
visual: '[Position Size] ████████░░░░ [Full Kelly]',
});
If the spaced repetition engine cannot load or save card data:
╔════════════════════════════════════════════════════════════════╗
║ ⚠️ STORAGE ERROR ║
╠════════════════════════════════════════════════════════════════╣
║ ║
║ Unable to load review cards from ~/.ari/learning/ ║
║ ║
║ Possible causes: ║
║ • Directory does not exist ║
║ • Insufficient read/write permissions ║
║ • Corrupted cards.json file ║
║ ║
║ Recovery options: ║
║ [A] Create directory and start fresh ║
║ [B] Restore from backup (cards.json.backup) ║
║ [C] View detailed error ║
║ ║
╚════════════════════════════════════════════════════════════════╝
Auto-recovery:
try {
const engine = await getSpacedRepetitionEngine();
} catch (error) {
if (error.code === 'STORAGE_INIT_FAILED') {
// Attempt to create directory structure
await fs.mkdir(path.join(homeDir, '.ari', 'learning'), { recursive: true });
// Initialize empty cards file
await fs.writeFile(cardsPath, JSON.stringify({ cards: [] }));
}
}
If SM-2 algorithm encounters invalid state:
// Cards with corrupted scheduling data are auto-repaired
if (card.interval < 0 || card.easeFactor < 1.3) {
// Reset to default values
card.interval = 1;
card.easeFactor = 2.5;
card.consecutiveCorrect = 0;
}
Update existing cards without losing scheduling history:
const updatedCard = await engine.updateCard(cardId, {
front: 'New question text',
back: 'New answer text',
// Scheduling data preserved
});
UI Flow:
╔════════════════════════════════════════════════════════════════╗
║ ✏️ EDIT CARD ║
╠════════════════════════════════════════════════════════════════╣
║ ║
║ Card ID: abc123 ║
║ Concept: Kelly Criterion ║
║ ║
║ Current Front: ║
║ "What is the Kelly Criterion formula?" ║
║ ║
║ New Front (or press Enter to keep): ║
║ [_____________________________________________] ║
║ ║
║ Current Back: ║
║ "f* = (bp - q) / b" ║
║ ║
║ New Back (or press Enter to keep): ║
║ [_____________________________________________] ║
║ ║
║ ⚠️ Scheduling data will be preserved ║
║ ║
║ [Save] [Cancel] ║
║ ║
╚════════════════════════════════════════════════════════════════╝
Remove cards permanently:
await engine.deleteCard(cardId);
Confirmation:
╔════════════════════════════════════════════════════════════════╗
║ 🗑️ DELETE CARD? ║
╠════════════════════════════════════════════════════════════════╣
║ ║
║ Card: "What is the Kelly Criterion formula?" ║
║ Concept: Kelly Criterion ║
║ ║
║ ⚠️ This action cannot be undone ║
║ ║
║ [Delete] [Cancel] ║
║ ║
╚════════════════════════════════════════════════════════════════╝
Suspend cards without deleting (for concepts no longer relevant):
await engine.archiveCard(cardId);
Archived cards are excluded from review queues but can be restored:
await engine.unarchiveCard(cardId);
Save cards as portable JSON:
const exported = await engine.exportCards();
await fs.writeFile('my-cards-backup.json', JSON.stringify(exported, null, 2));
Export Format:
{
"exportedAt": "2026-02-02T12:00:00.000Z",
"version": "1.0",
"cards": [
{
"id": "abc123",
"concept": "Kelly Criterion",
"front": "What is the Kelly Criterion formula?",
"back": "f* = (bp - q) / b",
"interval": 7,
"easeFactor": 2.5,
"nextReview": "2026-02-09T12:00:00.000Z"
}
]
}
Restore from backup or import shared decks:
const imported = JSON.parse(await fs.readFile('my-cards-backup.json', 'utf-8'));
const result = await engine.importCards(imported.cards, {
mergeStrategy: 'skip' // 'skip' | 'overwrite' | 'merge'
});
console.log(`Imported ${result.added} new cards, skipped ${result.skipped} duplicates`);
Import Conflict Resolution:
╔════════════════════════════════════════════════════════════════╗
║ 📥 IMPORT CONFLICT ║
╠════════════════════════════════════════════════════════════════╣
║ ║
║ Found 3 cards with matching IDs in your deck: ║
║ ║
║ Card 1: "Kelly Criterion" ║
║ • Your version: Interval 7 days, EF 2.5 ║
║ • Import version: Interval 1 day, EF 2.3 ║
║ ║
║ How should conflicts be resolved? ║
║ ║
║ [A] Skip (keep your version) ║
║ [B] Overwrite (replace with import) ║
║ [C] Merge (keep better scheduling data) ║
║ [D] Ask for each conflict ║
║ ║
╚════════════════════════════════════════════════════════════════╝
src/cognition/learning/spaced-repetition.ts - SM-2 engine with persistencesrc/cognition/learning/storage-adapter.ts - File-based persistencesrc/cognition/learning/retrieval-practice.ts - Socratic dialoguesrc/cognition/learning/concept-cards.ts - Card generationRelated Skills:
/ari-practice - Deliberate practice sessions that auto-generate review cards/ari-learning-mode - Comprehension checks that create cards for key concepts/ari-think - Deep reasoning that identifies concepts worth memorizingIntegration:
When you complete a /ari-practice session, cards are automatically generated for concepts where you struggled. These appear in your next review queue.
Workflow:
┌─────────────────────────────────────────────────────────────┐
│ │
│ [/ari-practice] → Practice generates cards for weak areas │
│ ↓ │
│ [/ari-review] → Daily reviews reinforce learning │
│ ↓ │
│ Cards mature over time (1d → 7d → 30d → 120d intervals) │
│ ↓ │
│ Long-term retention and mastery │
│ │
└─────────────────────────────────────────────────────────────┘
Cross-Domain Learning:
Review cards span all three cognitive domains: