FSRS Ruby - v6.0

A complete Ruby port of the FSRS (Free Spaced Repetition Scheduler) algorithm version 6.0. Claude Sonnet 4.5 by Antrhopic was used to generate this port.

Features

  • FSRS v6.0 Algorithm: Exponential difficulty formula, linear damping, 21 parameters
  • Short-term Learning: Minute-based scheduling with learning steps (e.g., ['1m', '10m'])
  • State Machine: NEW → LEARNING → REVIEW ↔ RELEARNING
  • Parameter Migration: Automatic migration from v4/v5 to v6 format
  • Fuzzing: Optional interval randomization using Alea PRNG
  • Strategy Pattern: Pluggable schedulers, learning steps, and seed strategies
  • Cross-validated: Outputs match TypeScript implementation to 8 decimal places

Requirements

  • Ruby >= 3.1.0

Installation

Add this line to your application's Gemfile:

gem 'fsrs_ruby'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install fsrs_ruby

Usage

Basic Example

require 'fsrs_ruby'

# Create FSRS instance with default parameters
fsrs = FsrsRuby.new

# Create a new card
card = FsrsRuby.create_empty_card(Time.now)

# Preview all possible ratings (Again, Hard, Good, Easy)
preview = fsrs.repeat(card, Time.now)

# Access results for each rating
good_result = preview[FsrsRuby::Rating::GOOD]
puts "If rated GOOD:"
puts "  Next review: #{good_result.card.due}"
puts "  Difficulty: #{good_result.card.difficulty}"
puts "  Stability: #{good_result.card.stability}"

# Apply a specific rating
result = fsrs.next(card, Time.now, FsrsRuby::Rating::GOOD)
updated_card = result.card

Custom Parameters

fsrs = FsrsRuby.new(
  request_retention: 0.9,           # Target 90% retention
  maximum_interval: 36500,          # Max interval in days (~100 years)
  enable_short_term: true,          # Use minute-based learning steps
  learning_steps: ['1m', '10m'],    # Learning: 1 minute, then 10 minutes
  relearning_steps: ['10m'],        # Relearning: 10 minutes
  enable_fuzz: false                # Disable interval randomization
)

Getting Retrievability

# Get memory retention probability
retrievability = fsrs.get_retrievability(card, Time.now)
# => "95.23%"

# Get as decimal
retrievability = fsrs.get_retrievability(card, Time.now, format: false)
# => 0.9523

Rollback and Forget

# Rollback a review
previous_card = fsrs.rollback(updated_card, review_log)

# Reset card to NEW state
forgotten = fsrs.forget(card, Time.now, reset_count: true)

Custom Strategies

# Custom seed strategy
fsrs.use_strategy(:seed, ->(scheduler) {
  "#{scheduler.current.id}_#{scheduler.current.reps}"
})

# Custom learning steps strategy
fsrs.use_strategy(:learning_steps, ->(params, state, cur_step) {
  # Return custom step logic
  {}
})

Algorithm Overview

State Transitions

NEW 
  • NEW: Card never reviewed
  • LEARNING: Initial learning phase with short intervals
  • REVIEW: Long-term review phase
  • RELEARNING: Re-learning after forgetting (lapse)

Ratings

  • Again (1): Complete failure, restart learning
  • Hard (2): Difficult to recall
  • Good (3): Recalled correctly with effort
  • Easy (4): Recalled easily

Key Formulas (v6.0)

Initial Difficulty (Exponential):

D

Next Difficulty (with Linear Damping):

Forgetting Curve:

R(t,S) = (1 + FACTOR 

Development

After checking out the repo, run:

$ bundle install
$ bundle exec rake spec

Cross-Validation

This implementation has been cross-validated against the TypeScript FSRS v6 implementation. All core formulas match to 8 decimal places.

See VERIFICATION_REPORT.md for detailed verification results.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/ondrejrohon/fsrs_ruby.

Please read CONTRIBUTING.md for details on how to contribute.

This project is intended to be a safe, welcoming space for collaboration. Contributors are expected to adhere to the code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Credits

This gem is a Ruby port of the TypeScript FSRS v6.0 implementation, developed with AI assistance and thoroughly cross-validated.

The FSRS algorithm was created by Jarrett Ye and the open-spaced-repetition community.

Verification

This implementation has been cross-validated against the TypeScript version with:

  • ✅ 125 passing tests
  • ✅ 89.87% code coverage
  • ✅ Algorithm accuracy to 8 decimal places
  • ✅ All known issues fixed and validated