A Spaced Repetition System is a study tool which works by spacing out exercises so as to learn in the most efficient manner possible. Further information can be found at the following Wikipedia pages:
srs is a command-line based implementation of the spaced repetition system. It
is designed to be highly extensible and to promote the sharing of data for study
srs is distributed as a Gem. Make sure you have Ruby and RubyGems installed,
and then type:
$ gem install srs
This first release of
srs is an alpha release -- it is functionally
complete, but the user interface is in its very early stages, documentation is
lacking, and there may be bugs. Since elements in the workspace format may
change, it is not recommended to use this version for actual practice. Treat it
as a "sneak preview". Version 0.2 is intended to be much closer to a final,
usable system, so please watch the project for updates on when that version is
With that in mind, read on...
Initialising a workspace
The first thing you will want to do once you've installed
srs is to initialise
a workspace. This is where all the data required for one set of material you
want to study reside. It is generally a good idea to group related items
together -- for example, I have a workspace for Japanese vocabulary, another for
kanji, and another for poetry and quotations which I'd like to remember.
How you think the things you want to learn should be distributed is a personal choice, and you should consider for yourself what will work best for you. For example, some people might prefer to put the Japanese vocabulary and the kanji together in one workspace -- that is fine. Merging or splitting workspaces at a later stage is relatively easy, so do experiment!
To initialise a workspace, create a directory and run the following command inside it:
$ srs init
Adding an exercise
srs, a single item of practice or revision is called an exercise. These
can be anything -- a flashcard-style question-and-answer, or a more interactive
form of practice. What a particular exercise entails depends entirely on what
it is you want to practice, and for that reason
srs introduces the concept of
A model is a Ruby class which defines how an exercise is performed.
packaged with the most basic kind of model, a flashcard, which is distributed
under the name
SimpleFlashcard. You can create your own models, but for now
we'll make use of the
SimpleFlashcard model to get something up and running
SimpleFlashcard exercise comes in two parts:
- The data, which usually contains the actual thing you want to test
- The exercise specification, which determines how to use that data.
This separation allows you to use the same data for multiple exercises. In this example, we're going to create a "Production" and a "Recognition" card for the Japanese word, 勉強, which means "study".
The first thing we need to do is create the DataFile.
currently expects its data to consist of a series of key-value pairs, separated
by a colon. Currently multi-line fields are not supported, though this will
change in a future version. Run the following from inside the workspace
directory you created (The ^D at the end signifies pressing Control-D to send
the end-of-file marker to
$ srs insert-into data Word: 勉強 Pronunciation (Hiragana): べんきょう Pronunciation (Romaji): Benkyou Meaning: Study ^Dc13d1e790ef5e8ced8c96a37a6d014f08ddcb3af
You should see the output after pressing ^D as above,
c13d1e790ef5e8ced8c96a37a6d014f08ddcb3af. The string itself may be different,
but it will be a long string of hexadecimal digits. The
reads data in from STDIN and outputs an ID which can be used by other
commands to access that data.
We now have data containing four fields related to the word. We can combine these fields in a variety of ways to generate a number of exercises. Here we'll generate two; one to produce the English meaning when shown the word and the pronunciation; the other to produce the Japanese word when shown the English. Input the following, substituting the value passed into the Data field with whatever was output from the previous command:
$ srs insert-into exercises Data: c13d1e790ef5e8ced8c96a37a6d014f08ddcb3af Model: SimpleFlashcard [Word] [Pronunciation (Hiragana)] --- [Meaning] ^D884bd92624411f5bb42ff9abdf84c3e09ba00cab
Note the blank line between the set of key-value pairs and the text below.
SimpleFlashcard expects a series of headers, followed by a blank line,
followed by some metadata. The metadata is in two parts: the question, which is
everything before the "---" string, and the answer, which is everything that
comes after it. Any words within square brackets are substituted with the value
of their corresponding field in the data.
As with the previous command, this command outputs an ID once it has completed. Remember this; you will need it later. Let's add the second exercise:
$ srs insert-into exercises Data: c13d1e790ef5e8ced8c96a37a6d014f08ddcb3af Model: SimpleFlashcard [Meaning] --- [Word] ^Dd930b3fce3d2f988758c7088ea77d9075b8c82bf
As you can see, this is just the same exercise, with the question and answer reversed. Also, we are ignoring pronunciation for this one.
You will notice, neither of these exercises make use of the "Pronunciation (Romaji)" field. The truth is, I don't much like Romaji. But it is entirely reasonable to add fields you won't use as part of the exercises to the data; you may choose to create exercises which make use of that data later, or you may just want to look it up (for example, you could include the link to a URL where you discovered the information).
Scheduling an exercise
The next thing we must do is schedule the exercises we've just created. If we
don't do this, they will never enter the
srs scheduling system, and so they
will simply sit there unasked!
There have been a number of spaced repetition algorithms developed over the
years, perhaps the most famous of which are the Pimsleur Graduated Recall
and SuperMemo 2 algorithms. As with models,
srs allows you to define
your own custom spacing algorithm by creating a scheduler. The base
distribution comes with probably the most popular spacing algorithm
pre-installed, SuperMemo 2. We'll use that one.
Type the following, substituting the two ids with the ones returned when you inserted the two exercises:
$ srs schedule -s SuperMemo2 884bd92624411f5bb42ff9abdf84c3e09ba00cab schedule/pending/20120708003132.386 $ srs schedule -s SuperMemo2 d930b3fce3d2f988758c7088ea77d9075b8c82bf schedule/pending/20120708003149.754
Doing some reps -- new exercises
Now that you've scheduled some exercises, you're ready to do some reps. Let's
srs what the next new exercise is which is available for learning:
$ srs next-new 20120708003132.386
The ID of the first exercise you scheduled above should be output. In order to
actually test ourselves, we'll need the ID of the exercise we want to run. We
can get this from the
Exercise field stored in the schedule (as always,
remembering to substitute the example ID below with your own):
$ srs get-field exercise 20120708003132.386 884bd92624411f5bb42ff9abdf84c3e09ba00cab
An exercise ID will be output, which we can feed straight into
$ srs do-exercise a884bd92624411f5bb42ff9abdf84c3e09ba00cab 勉強 べんきょう >
At this point you are given a prompt. Let's enter the correct answer, "Study", and see what happens:
> Study Correct. You scored: 1.0
srs are normalised from 0-1, so 1.0 is a full score. Well done! We
still need to enter this into the scheduler so that it knows when next to repeat
the exercise. Enter the following to reschedule the exercise. The ID is the
schedule ID, not the one for the exercise:
$ srs reschedule 20120708003132.386 1.0 Exercise rescheduled for 2012-07-09 00:00:00 +0900
Excellent! We'll see this exercise again tomorrow.
It's actually possible to wrap up most of the above in a single line. The
following assumes you use a
bash shell, though other shells may be similar:
$ SCHEDULE=$(srs next-new); EXERCISE=$(srs get-field exercise $SCHEDULE); srs do-exercise $EXERCISE
This time we'll try answering the question incorrectly:
Study > 遊ぶ 勉強 Was your answer: [h] Correct, [j] Close, [k] Wrong, or [l] Very Wrong? > l You scored: 0.0
When you enter a wrong answer, the
SimpleFlashcard doesn't attempt to judge
for itself whether or not you were close to the right answer. Instead, it shows
you the correct answer and lets you specify how close you thought you were. In
this case, we were miles off, so we selected 'l', to fail the exercise
completely. Now to reschedule the exercise:
$ srs reschedule $SCHEDULE 0.0 Exercise rescheduled for 2012-07-09 00:00:00 +0900 Exercise failed; marked for repetition
Since we failed the exercise, the scheduler has marked it for repetition. This means that once we've finished all our scheduled reps for the day, we will be presented with this exercise (and any other failed exercises), to try again until we have managed to pass them. Note that only the first attempt affects the interval; subsequent repetitions are simply practice.
Practice makes perfect! Repeating exercises
For the most part, you're going to be practicing exercises you've already done
once. The flow for this is very similar to the above, except that instead of
next-new we use the
Before we can use this command, however, we need to update the srs queue:
$ srs queue
This command tells
srs to look through the schedules and determine which
exercises are due for practice. We can now use
next-due similarly to the
way we practised new exercises in the previous section:
$ SCHEDULE=$(srs next-due); EXERCISE=$(srs get-field exercise $SCHEDULE); srs do-exercise $EXERCISE Study > 勉強 Correct. You scored: 1.0 $ srs reschedule $SCHEDULE 1.0 Exercise rescheduled for 2012-07-09 00:00:00 +0900
In this case, since the exercise had already been scheduled and was simply a repetition of a failed exercise, the date matched that which was output previously.
Finally, we can confirm that there are no more exercises left to practice:
$ srs queue $ srs next-due
srs is in very early stages and as such there is a lot of work still to do
on it. Contributions are welcome!
To contribute, fork the project on github and send me a pull request, or email me a patch. Please bear the following in mind when making contributions:
- Try and keep individual commits small and self-contained. If I feel like there is too much going on in a single commit, I may ask you to split it up into multiple commits.
- Please write clear, descriptive commit messages. These should be formatted
with a title of
<=50 characters, and body text wrapped at 72 characters. I am quite particular about this.
- I come from a pretty heavy C++ background. Ruby style corrections and improvements are very much appreciated! Please be nice about it.
Copyright (c) 2012 Daniel P. Wright.
This software is released under the Simplified BSD Licence. See LICENCE.md for further details.