Metadata-Version: 2.5
Name: abhyasa
Version: 0.0.12
Summary: A tutor that asks you questions: active recall, a learner model and a concept graph in your vault
Project-URL: Repository, https://github.com/vedicreader/abhyasa
Project-URL: Documentation, https://vedicreader.github.io/abhyasa/
Author-email: Karthik <karthik.rajgopal@hotmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: active-recall,learning,nbdev,spaced-repetition,vishalakshi
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Education
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Requires-Python: >=3.12
Requires-Dist: fastcore>=1.8
Requires-Dist: fossick>=0.1.22
Requires-Dist: ipywidgets>=8.1
Requires-Dist: mdhtml>=0.1.38
Requires-Dist: nh3>=0.3.7
Requires-Dist: python-fasthtml>=0.14
Requires-Dist: rishi>=0.1.56
Requires-Dist: rupaka>=0.0.6
Requires-Dist: vidyut>=0.4
Requires-Dist: vishalakshi>=0.1.35
Provides-Extra: demo
Requires-Dist: rupaka[check]>=0.0.6; extra == 'demo'
Provides-Extra: dev
Requires-Dist: ipykernel>=7.3.0; extra == 'dev'
Requires-Dist: nbdev>=3.3.25; extra == 'dev'
Requires-Dist: notebook>=7.6.3; extra == 'dev'
Requires-Dist: pobblebonk>=0.0.6; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: rupaka[check]>=0.0.6; extra == 'dev'
Provides-Extra: models
Requires-Dist: ramabana>=0.2.78; extra == 'models'
Provides-Extra: tick
Requires-Dist: pobblebonk>=0.0.6; extra == 'tick'
Provides-Extra: whisper
Requires-Dist: mlx-audio>=0.5; extra == 'whisper'
Description-Content-Type: text/markdown

# abhyasa


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

<img src="https://raw.githubusercontent.com/vedicreader/abhyasa/main/design/logo/abhyasa-icon.png" width="128" alt="abhyasa logo">

[![Download for macOS](https://img.shields.io/badge/Download_for_macOS-Abhyasa.zip-2F2722?style=for-the-badge&logo=apple&logoColor=white)](https://github.com/vedicreader/abhyasa/releases/download/mac-v0.0.10/Abhyasa.zip) [All releases](https://github.com/vedicreader/abhyasa/releases)

[![](https://github.com/vedicreader/abhyasa/actions/workflows/test.yaml/badge.svg)](https://github.com/vedicreader/abhyasa/actions/workflows/test.yaml)

abhyasa (अभ्यास) is Sanskrit for “steady practice”. It is a tutor for people who want to learn well and keep their minds active. It asks you questions, and it never gives the answer first. You answer by voice or in text, and you can think aloud. The tutor grades your reasoning, not only the result.

abhyasa keeps a learner model for each concept: how deep you know it, how well you recall it now, and when you must review it. It also learns how you learn. If code helps you more than equations, it uses code to teach a weak concept again. Sometimes it uses a different way on purpose, so that you get better at that way too.

The app needs macOS 26 on Apple Silicon. The tutor uses a language model. You choose it from a list in Settings, for example Claude, GPT or a local model. Your answers go to that model. Speech to text runs on your Mac by default. All other data stays in your vault on your Mac.

## Download

Click the Download for macOS button at the top. Then do these steps:

1.  Unzip `Abhyasa.zip`.
2.  Move `Abhyasa.app` to Applications.
3.  Open Abhyasa.
4.  Wait for the first start. The app uses uv to get Python and the abhyasa package one time. This step takes some minutes.

The app needs uv. If you do not have uv, install it with `brew install uv`. Each release has a Developer ID signature. Apple notarized each release.

### Homebrew

``` sh
brew install --cask vedicreader/tap/abhyasa
```

The cask also installs uv. To get a new version, run `brew upgrade --cask abhyasa`. To remove the app, its settings and its Python environment, run `brew uninstall --zap --cask abhyasa`. The zap does not remove your vault, because other tools use it too.

## How it works

Each question goes through the same six steps:

1.  Pick. The code chooses the next concept and the depth. A due review comes first. Then a new concept comes, if you know its prerequisites. The app shows the reason.
2.  Ask. A model writes one question at that depth, in one way to learn, such as code or an analogy. It also writes a correct answer and a rubric. You do not see them.
3.  Struggle. You answer. If your answer is wrong, the tutor shows your first error. It gives a small hint, but not the fix. You can ask for hints, one at a time.
4.  Grade. The model grades your answer and your think-aloud. The code grades choice questions and code exercises.
5.  Update. The result and your confidence change the floor, the ceiling and the next review date of the concept.
6.  Teach. After a miss, the tutor teaches the smallest step that fixes your first error. Then it asks a check question.

When you say “I don’t know X”, X becomes a concept, and it comes first the next time. The Strengths page (⌥G) shows your strong concepts, your weak spots with their reasons, and the ways that you learn best. “Practice my weak spots” starts a session on your weakest concepts.

| term | meaning |
|----|----|
| concept | one idea that the tutor can ask you about |
| depth | 0 unseen, 1 recognise, 2 recall, 3 explain, 4 apply, 5 transfer |
| floor | the highest depth that you pass every time |
| ceiling | the lowest depth where you failed |
| attempt | one answer, kept as a document in your vault |
| session | one sitting of questions. abhyasa saves it after each step, so you can continue it after a restart |
| journey | a goal and a path to it, with one concept for each step. You can see and change the path |
| profile | what abhyasa knows about you: your background, your goals, the examples that help you and your pace. You can see and change all of it |
| way to learn | code, maths, an analogy, a worked example, a picture or plain words. Each result counts for the way that the question used |
| gap | an idea that you said you do not know. It comes before the concept where you said it, but it does not block that concept |
| hint | one step on a ladder of six, from the least to the most help |
| lesson | the smallest step that the tutor teaches after a miss. “Another way” (⌥A) teaches it again in a different way |
| demo | an interactive figure for one concept. You predict, you lock in, and then you change the inputs |

## Learn a paper, a topic or a link as a walk

A walk takes you through one source, one idea at a time. You can make a walk from a paper in your vault, a text that you paste, a topic, or a link. Use Add, and choose what you have.

The tutor reads the source and picks the main ideas. A walk has 12 ideas by default. You can change this number in Settings, under Walks. Before you start, the plan page shows each idea and the kind of check for it. You can change the kind for an idea there.

Each idea is one step. A step shows the passage from the source, word for word. It also shows a short note from the tutor and a figure from the source, if the source has one. Each step has one check:

- Short answer. You write the idea in your own words, and the tutor grades it.
- Demo. You predict what a demo will do, lock in your prediction, and then change the inputs.
- Order. You put the parts of the idea in the right order.
- Code. You write a small Python function, and its tests run.

The tutor picks the kind that fits the idea and your profile. The step shows the reason. Reading never waits for a check. You can read the passage and press “Skip this idea” at any time. A skipped idea stays unseen in your record. A pass or a miss on a check changes your record, as an answer in a session does.

On a walk step, ⌥S sends your answer, or runs the tests. When the check is closed, ⌥S goes to the next idea. ⌥W asks for a hint. In a demo, ⌥V keeps the state of the demo. ⌥F still shows all the keys.

### Code runs in a closed process

The tests of a code check run in a closed process with no network. Each test has 2 seconds, and the whole run has 10 seconds. You can change these limits in Settings, under Code runner. On macOS, a `sandbox-exec` profile stops the network and stops writes outside a temporary folder. On other systems, the guard is best-effort, so run abhyasa in your own container if you need more. abhyasa installs no libraries. Its code checks use only the Python standard library.

### A walk from a link

On Add, choose “A link”. These links work: a web page, a documentation site, a PDF, an arXiv link or id, and a GitHub repository or file. A video link does not work. A link to your own computer or to a local network does not work either.

abhyasa fetches the link only when you press “Make a walk”. It reads only the pages in the folder of the link, after any redirect. It reads at most the page cap. The default is 8 pages. You can set the number on Add, up to the cap in Settings, under Links. The cap is 20 by default.

## Rabbit holes

A passage can use an idea that you do not know yet. The step then shows a “This needs” line with each idea that it needs. An idea that is not learned yet has a “Learn beside” button.

You have three choices:

1.  A quick primer. A short text that you read in the side pane.
2.  A short side walk. A small walk on that idea, in the side pane.
3.  Its own session. A normal session on that idea, in a new tab.

Press ⌥B to open the offer. Then press 1, 2 or 3. A primer or a side walk opens in a pane beside the step. The paper stays on the left. On a narrow window, the side walk opens in the same tab, with “Back to the paper” at the top.

- ⌥B opens the offer for the first idea that you do not know.
- ⌥Z goes back to the paper and closes the pane. Esc also closes it.
- A side walk can open another side walk. The limit is 2 levels, and you can change it in Settings, under Walks. Past the limit, only “Own session” is left.
- The check that was open on the paper stays open. The answer that you typed there stays in the box. When the side walk ends, the paper tells you what you learned on the way.

The pane opens only pages of abhyasa. A pane address that points to another site is ignored.

## Teach a topic to a group

You can present a walk to a group, as a talk. Each idea of the walk becomes one slide. The passage and the figure, or the demo, show to the room. The tutor note becomes your speaker note. The check of the idea becomes a question for the room.

### Make a talk from a walk

On the plan of a walk, or on its journey page, press “Present this walk”. The editor shows the slides in the order of the walk. A Questions slide and a recap slide come at the end. Set the minutes of your slot. A change to the talk does not change the walk.

In the editor, W and S move the focus from slide to slide. ⇧W and ⇧S move a slide up or down. E opens the form that changes the slide. X takes out the slide (press X again to be sure). Q adds a pause after it. In the form, each line of “Beats” is one press of D: [`passage`](https://vedicreader.github.io/abhyasa/ground.html#passage), `figure`, `demo`, `ask`, or `lit:` and words from the passage. A `lit:` beat lights those words on the slide.

In this version the room answers with hands. Keep “Room phones” at “No phones”.

### The two windows

Press Present (⌥S). The presenter window shows the slide now, your notes, the next slide, the question card and a clock. The first key that you press opens the audience window. If the browser blocks it, use the link “Open the audience window” at the top.

To show the audience window on the projector, move it to the projector screen and press F in it. F fills the screen. Another key in the audience window only shows a note: the keys work in the presenter window. A reload of the audience window shows the same slide and beat. If you close the audience window, the presenter window tells you, and gives a link to open it again.

The two windows send messages only to each other, in the same browser. Each run of a talk has a new random key. Thus an audience window from an old run cannot show or change a new run.

The Abhyasa app for Mac cannot open the second window. In the app, the presenter window shows the address of the talk. Open that address in your browser to present.

### The keys of a talk

All keys work in the presenter window. They do not work while the focus is in a text box or in the demo.

| key | what it does |
|----|----|
| D, space, → or Page Down | the next beat, then the next slide. With a primer open: its next page. A clicker works too |
| A, ← or Page Up | back one beat. With a primer open: its page before |
| G, then a number | go to that slide |
| Q | ask the room, or close the question |
| R | show the right answer |
| 1 to 6 | while a question is open: the option that most hands chose |
| E | go into the demo. Esc comes out |
| X | the laser on or off. Move the pointer over the slide, and a dot shows in the audience window |
| B | blank the room screen, and back |
| ⌥S | the main button: ask the room, show the answer, close the question. On the last slide it ends the talk |
| ⌥B | open a primer beside the slide |
| ⌥Z | close the primer |
| Esc | close the open question, the demo focus or the side pane. Esc never ends the talk |

In a talk window, ⌥T, ⌥C, ⌥G, ⌥D and / do nothing. Thus a key that you press by mistake does not take you away from the talk.

### Ask the room with hands

Press Q. The question and its options show in the audience window. The answer does not show. The people in the room put up their hands. Press the number of the option that most hands chose: 1 for A, 2 for B, and so on. Then press R. The right answer and the answer of most hands are lit. After R, “Talk to your neighbour” lets the room talk in pairs about the answer.

On a slide with a demo, press E to go into the demo and change it. The demo in the audience window follows each change. When you choose an answer at a gate of the demo, the room sees your answer. The room sees if your answer is right only after R. If you press “Try another”, the gate opens again in both windows.

### The side pane in a talk

Press ⌥B to see the ideas that the slide needs. Press 1 for a quick primer, or 2 for a short side walk. The primer opens beside the slide in both windows, in large type. It has no check. A long primer shows one page at a time: press D for the next page and A for the page before. While it is open, Q asks the room a question about the primer. ⌥Z closes the pane in both windows. A move to a new slide also closes it. A side walk from a talk does not show in your journeys or in Continue.

### After the talk

On the last slide, press ⌥S, or press “End the talk” at the top. The audience window says “Thank you”, and the presenter window opens “After the talk”. This page shows:

- where the room was unsure: each question, with the answer that most hands chose;
- the talk, slide by slide, with the time of each slide and each primer beside it;
- “Save the recap as one file”: one HTML file with the slides, the passages, and each question with its right answer and the result of the room. It has no speaker notes and no names. Send it by mail or chat. “Look at it first” opens it in the browser;
- a follow-up walk on the ideas where the room was unsure, and the primers that you can put in the talk for the next time.

### The room does not change your learning

The answers of the room are counts in the talk. They are not your attempts. Your own pick at a demo gate in a talk is not an attempt either. A talk does not change your record, your Continue or your journeys.

Settings has a Talks group. It has the minutes for each question, the time to talk to a neighbour, the share of right answers below which a slide is unsure (70% by default), and how long the laser dot stays.

## Open in Leela

abhyasa does not install libraries for you, and it runs only short exercises that use the standard library. A library or a command-line tool is better to learn in [Leela](https://github.com/vedicreader/leela). Leela has the tool environments, code lookup and an agent tutor.

When you add a link, tick “It is a library or a command-line tool”. This makes a tool walk. A tool walk asks short-answer and order checks here, and it has no code check.

A step that needs code has an “Open in Leela” link. The link opens Leela in a new tab, on the same walk and step. abhyasa never calls Leela. It reads the file that a running Leela writes, and it makes a link only to an address on this computer.

If Leela does not run, the step says so, and it links to the install page.

## Settings

Settings has every value that you may want to change. The values are in 12 groups:

| group | what it sets |
|----|----|
| Look | the theme and the mode |
| Learning | your pace, how many questions a session has, and how often the tutor tries a new way to teach you |
| Walks | how many ideas a walk has, how much is hands-on, how deep a side walk goes, and the length of a passage and a note |
| Talks | the minutes for each question, the time to talk to a neighbour, when a slide is unsure, and the laser |
| Checks and grading | the tries for a check, how close an answer must be to pass, hints, and how sure you must be |
| Review | when a concept comes back, and a limit for each day |
| Links | the page cap, the time for a link, and how much text abhyasa keeps |
| Code runner | the time for each test, the whole run, and the size of a file that code writes |
| Speech to text | the speech engine, the pause that ends a phrase, and the longest phrase |
| Models | the model for each tutor task, and the limit of its reply |
| Lists | how many rows each list shows |
| Prompts | the text of the tutor prompts |

Each number has a range. The page shows the range and the default next to the value, for example `3 to 30 · default 12`. A value outside its range is not kept. If your settings file has such a value, abhyasa uses the nearest end of the range and tells you on the page. Where a value is not the default, “Use the default” puts the default back. “Use the defaults for this group” does the same for the whole group. “Find a setting” filters the rows as you type.

Some guards have no setting: the closed process with no network, the check of link addresses, plain HTTP for web pages, the check of a pane address, and the rule that abhyasa answers only this computer. A change to a setting works on the next question or the next walk.

## Keyboard shortcuts

All keys are for the left hand. ⌥ is the Option key. To see all the keys, press ⌥F, or press ? outside a text box.

If you use [Sanketa](https://github.com/vedicreader/sanketa), it shows the same keys when abhyasa is in front. abhyasa writes the pack `~/.config/sanketa/packs/abhyasa.toml` when it starts. It does not write over a pack that you made.

## Run from source

Install the package and its dependencies:

``` sh
uv sync
```

Start the web app on <http://127.0.0.1:5077>:

``` sh
uv run abhyasa
```

The app answers only requests from this Mac. These variables change the defaults:

| variable | what it sets | default |
|----|----|----|
| `ABHYASA_VAULT` | the vault file | your vault: `$VISHALAKSHI_VAULT`, then `~/.vishalakshi/vault.db` |
| `ABHYASA_MODEL` | the model id for questions, grades, hints and lessons. Choose the model in Settings. | `claude/sonnet` (Claude Sonnet) |
| `ABHYASA_STT` | the speech-to-text engine: `gemma`, `whisper`, `parakeet`, `openai` or `mlx:<repo>`. It has priority over the Settings page. | the Settings page, then `gemma` |

## Other ways to use it

The web app, the terminal and the notebooks use the same tutor and the same data.

### The web app

The web app is made from blocks in `abhyasa/blocks`:

| block | what it does |
|----|----|
| `today` | the home page: continue, the next review and your journeys |
| `journeys` | say a goal, and the tutor makes a path of steps. You can move, skip, add or split a step |
| `history` | your learning: each past session with what changed, and what you learned each week. Continue (⌥C) is in the top bar |
| `profile` | what abhyasa knows about you: a short first conversation, your edits, and the changes that the tutor makes, each with its reason |
| `strengths` | your strong concepts, your weak spots and the ways that you learn best (⌥G) |
| `session` | one sitting with the tutor: one question at a time, with hints, confidence and “I don’t know” |
| `voice` | a microphone for each text box. ⌥D speaks into the box that has the focus, on any page |
| [`settings`](https://vedicreader.github.io/abhyasa/settings.html#settings) | every value that you may change, in groups: the look, learning, walks, checks, review, links, the code runner, speech, models, list lengths and the tutor prompts. Each number shows its range and its default. A change works on the next question |
| `concepts` | the list of concepts, and one page for each concept with its state |
| `graph` | the concept graph. You can color it by depth, by how well you know each concept, by subject or by due date |
| `search` | one search over the `learning` shelf and the other shelves of your vault |
| [`add`](https://vedicreader.github.io/abhyasa/settings.html#add) | make a walk, or find concepts, from a text, a vault document, vedicreader or a link |
| `walk` | a walk: one step for each idea, with a passage, a note and a check |
| [`detour`](https://vedicreader.github.io/abhyasa/journey.html#detour) | rabbit holes: a primer, a side walk or a session for an idea that a step needs, with the side pane |
| `demo` | interactive demos from rupaka: on a concept page, under a lesson after a miss, and one page for each demo |
| `keys` | the keyboard shortcuts (⌥F) |

Each page shows where you are, above its title. Esc goes up one level, ⌥T goes to Today, and Back and Forward work.

### ramabana

In the ramabana terminal agent, the `/learn` extension gives you the tutor next to your code. To turn it on, make the file `~/.config/ramabana/extensions/abhyasa.py` with this line:

``` python
from abhyasa.rama import setup
```

### Notebooks

In leela or Jupyter, [`learn`](https://vedicreader.github.io/abhyasa/nb.html#learn) shows a question card. [`exercise`](https://vedicreader.github.io/abhyasa/nb.html#exercise) gives a code exercise, and its tests run in the kernel.

``` python
from abhyasa.nb import learn, exercise
learn('reciprocal-rank-fusion')
ex = exercise('reciprocal-rank-fusion')
```

## Where the data is

All data is on the `learning` shelf of your vault. Each concept, attempt and session is one document in the vault. Thus your other tools can search it. The tests use a vault in a temporary folder. They never open your real vault.

## Demos

Some ideas are easier to see than to read. A demo is one interactive figure from [rupaka](https://github.com/vedicreader/rupaka). It asks you to predict first. It hides the result until you lock in (⌘↩). Then the controls work, and the last line asks a new question.

- The tutor makes a demo after two misses on a concept with the same kind of error. It also makes one for a concept with `visual: true` in its meta. The model writes the demo as data. rupaka checks it in a headless browser. You do not wait for it.
- After a miss on a concept that has a demo, the session shows the demo under the lesson.
- “Show me a demo” (⌥E) on a concept page shows the newest demo, or makes one.
- abhyasa keeps each prediction as an attempt with `kind='demo'`. A prediction changes the learner model of the concept, as an answer does. A prediction with a reason counts at depth 3 (explain). A prediction without a reason counts at depth 2 (recall).

`abhyasa.demo.import_gallery(learning)` keeps the rupaka gallery demos, such as vowel sandhi, for the concepts that match.

## Example

This example runs offline. [`temp_learning`](https://vedicreader.github.io/abhyasa/store.html#temp_learning) makes a shelf in a temporary vault, and [`Fake`](https://vedicreader.github.io/abhyasa/llm.html#fake) takes the place of the model.

``` python
from abhyasa.store import temp_learning
from abhyasa.llm import Fake
from abhyasa.tutor import Tutor

lr = temp_learning()
lr.put('Ranking', 'Order items by a score.', 'ml')
fake = Fake({'You grade one answer': dict(correct=True, grade=8, first_error='', misconception='', feedback='Yes. Only the order counts.')},
            dflt=dict(question='Why can you compare ranks from two systems, but not their scores?', answer='Ranks share one scale.', rubric=['ranks share one scale']))
t = Tutor(lr, fake, context=False)
```

Ask the first question. `why` gives the reason for the choice, and `method` gives the way to learn that the question uses. A new concept starts at depth 3 (explain).

``` python
q = t.next()
assert q.why.startswith('next on the frontier: its prereqs are in place')   # a note on the way to learn can follow
assert q.depth == 3
print(q.question)
```

Answer with high confidence. A `solid` pass at depth 3 changes the floor to 3.

``` python
r = t.answer(q.id, 'A rank is a position, and positions use the same scale in each list.', confidence=80)
assert r.outcome == 'solid'
assert lr.concept('ranking').floor == 3
```
