Lani GitHub

Dobro jutro! Dobrodošli v vasi. Good morning! Welcome to the village.

Lani

Learn Slovene by living in a little village.

An Android game with a pixel-art village whose people speak to you, a grammar book that opens as you go, and your own Claude Code session as the tutor behind it, writing new dialogs, stories and exercises as you progress.

Read this page in

Early, active development · one daily learner · self-hosted · AGPL

The village, recorded on the emulator: drawn in code, every pixel of it.

07:30 Dobro jutro · Buongiorno · Guten Morgen · Good morning

Štiri vasi, štirje jeziki Four villages, four languages

Lani has four villages, each in its own language and its own corner of the Alps and beyond: Slovene in Primorska, Italian in Friuli, German in Kärnten and English in the Lake District. Each has its own people, stories, feasts and food. The app's interface speaks Slovene, English, German and Italian, and pairs any two of them: the language you learn, and the one it's explained in.

The villagers talk to the learner by name, and their lines agree with the learner's gender, as the language needs: Slovene fant or dekle, Italian ragazzo or ragazza.

The app's labels, in pairs

    🇸🇮 Primorska

    The learner:

    The storyteller

    Tonight by the fire

      All of it is real content from the app's culture packs (companion/cultures/), machine-written and marked so until a native speaker has read it. The screenshots are the app on the emulator, visiting sample towns.

      09:00 Tone kuje podkev · Tone is forging a horseshoe

      Dan v vasi A day in the village

      A dozen villagers live their own days. France mows in the dew and harvests his field, Tone forges at the smithy, Babica Micka bakes potica and brings soup to the fire, and every evening Stari Janez tells a legend there. They ask for help in Slovene: a bubble over someone's head is a request, a little exercise in what they need.

      What you do for them builds the village. It starts as a campfire in a clearing and grows with the words you learn, age by age, towards your target level:

      1. Ogenj Campfire
      2. Tabor Camp
      3. Zaselek Hamlet
      4. Vas Village A2
      5. Trg Market town B1
      6. Mesto Town

      The village keeps time with yours: mornings, rain, the moon, a merchant from Gorizia at the gate, a feast under the linden. Its sounds are synthesized in code too. Have a listen:

      1. France kosi v rosi France mows in the dew
      2. Tone kuje podkev Tone is forging a horseshoe
      3. Mojca pri vodnjaku: dvojina! Mojca at the well: the dual!
      4. Tine zvoni poldne Tine rings the noon bell
      5. Otroci igrajo nogomet The children are playing football
      6. Babica prinese juho Grandma brings soup
      7. Janez pripoveduje zgodbo Janez tells a story
      8. Sova se oglaša An owl is calling
      The same village after dark: Stari Janez has a story, Babica Micka brings soup.

      10:30 Zala bi se igrala skrivalnice · Zala wants to play hide-and-seek

      Prizori in pogovori Scenes and dialogs

      Every place of the village opens into a close-up: indoors an isometric diorama, outdoors a view to the hills. You find the words in the picture by tapping the things in it, and you talk to whoever is there today.

      The kitchen as an isometric diorama: a stove, a table with bread and a jug, shelves, a red-checked curtain, a vegetable bed outside the wall.
      V kuhinji In the kitchen
      The field as a view to the hills: a hayrack full of hay, a horse and cart on the path, a scarecrow, cabbages, a hare, a church on the hill behind.
      Na njivi In the field

      Find the words in the picture

      Tap the scarecrow and it says strašilo, with its gender and plural and a sentence to go with it. Some things show only at dawn, by night, or not in winter; the panel under the picture keeps count of what's here now, what you've seen before and what's still hidden.

      Talk to people, your way

      A dialog's turns adapt to what you know. While a rule is new, you choose; once you have it, you type the missing word; some turns are answered by tapping the picture, and any turn can be said aloud instead. The dialogs only ask for what the grammar book says you've met.

      Babica prinese juho Grandma brings soup

      In the evening Babica Micka brings soup to the fire. Three answers, one right: the others are near misses that teach something (žejen is thirsty, dobro jutro is for the morning).

      Dober večer, Jan! Si lačen? Good evening, Jan! Are you hungry?

      Try it: tap a word

      Every line in the app is made of words you can tap. Each opens its card: the dictionary word, what this form is, its meaning, its partner, its forms.

      Babica Micka

      ! , .

      Good evening! Sit down, sit down.

      Tap a word on the left.

      11:30 Mojca pri vodnjaku: dvojina! · Mojca at the well: the dual!

      Slovnica The grammar book

      The village scroll, a book once the hamlet is a village, has a page for every rule: 44 for Slovene, from biti to the six cases, aspect and the dual. A page is written in the first time you meet its rule in an exercise, and its stars say how well you know it.

      Rules you've only met in the dialogs wait, greyed: »Še ne«, not yet. The dialogs and the word forms only ask what the book has opened, your mistakes show up on the rule's page, and the tutor can write a new page when you need one.

      The village scroll's grammar section: rules met so far with their stars (adjectives, adverbs, the genitive after prepositions), and greyed pages only met in the dialogs (the instrumental, the dative).
      A grammar page, Tožilnik: pijem kavo, vidim brata (the accusative), with the rule, a table of noun kinds and examples to listen to.

      The six cases, on one house

      Each case has its school questions. Ask the question, and the answer takes its case. Pick a row.

      CaseQuestionsForm
      1. imenovalniknominativekdo? kaj?hiša
      2. rodilnikgenitivekoga? česa?hiše
      3. dajalnikdativekomu? čemu?hiši
      4. tožilnikaccusativekoga? kaj?hišo
      5. mestniklocativepri kom? pri čem?pri hiši
      6. orodnikinstrumentals kom? s čim?s hišo

      Luka šteje ovce · Luka counts his sheep

      Slovene has a dual: one form for exactly two. After a number the noun changes, and so does the verb.

      12:00 Tine zvoni poldne · Tine rings the noon bell

      Besede in oblike Words and their forms

      Words stay with spaced repetition (SM-2): a card comes back just before you'd forget it. A word you remember each time waits longer and longer:

      1. 1 day
      2. 6
      3. 15
      4. 38
      5. 94 days

      The cards take many forms: flashcards, listening, dictation, speaking. Once you know a word, its forms come too: its conjugations and cases, as far as the grammar book has opened them, each in a sentence from the village. »Zaklenjene odpre stran v knjigi«: a page of the book opens the locked ones.

      A villager keeps you company in the reviews. In the clip it's Teta Ančka: »Kaj? Kdo ste? Glasneje!« (What? Who are you? Louder!)

      Vstavi pravo obliko · Fill in the right form

      16:00 Na poti domov · On the way home

      Za pot In the car

      For long drives there's an Android Auto mode: audio drills prepared on the phone ahead of time and played with the steering wheel's buttons. You hear the meaning, say it aloud, then hear how it's said and repeat it.

      • Preobrat Transformations: Micka kuha kosilo. Into the past! → Micka je kuhala kosilo.
      • Hitri odziv Rapid fire: a number, a time, a date, two seconds to say it.
      • Gradnja stavkov Sentence building: a sentence grows a step at a time.
      • Uganke Riddles: Stari Janez describes a thing of the village in three or four clues.
      The phone's player during a drive: it shows only the meaning (snow, oven, to think), you say the Slovene first. Sped up 2.5×.

      Med vožnjo ne glej na zaslon. While driving, don't look at the screen.

      The car's sheet in the app, 🚗 Za pot · For the road: everything for the road is on the phone, 14 minutes to listen to, and the sessions: for the road, easy listening, shadowing, reviews, new words, dialogs, stories, transformations.

      17:30 Na obisku · Visiting

      Obiski Visiting each other

      Every learner's village is a town of its own, and towns can link up: two learners, each with their own tutor, can visit each other's village. Towns are linked only by invitation, with a one-time QR code or code that works for 30 minutes. There's no directory.

      A visit happens in the host village's language. Visit an Italian town and its labels read In visita · Visiting, its people greet you in Italian, and everything you learn there goes to your Italian. Both learners practise the language of the village they're in.

      Things to do on a visit

      • Requests: help the town's people with a run of their words, and they thank you with something from their chest.
      • A gift: something from your chest and a short message, written in the town's language.
      • The market: pick what you'd like, offer something of yours, and haggle; your tutor plays the seller.
      • A question for the host: ask in their language; they answer in it. Each tutor checks its own learner's sentence first, if they like.
      • Talk: the town's people, played by your own tutor, in the town's language.

      A friendship both towns agree on

      Visits, help, gifts, trades and answered questions count for the towns' friendship, which grows through five levels. Each brings something: better rates at the market, help when wolves or a storm come, a shared feast, people moving between the towns. Both towns compute the level from the same counts, and an act counts once both have it, so a friendship that one learner keeps up alone stops at the middle.

      1. Znanstvo Acquaintance
      2. Dobro sosedstvo Good neighbours
      3. Prijateljstvo Friendship
      4. Tesno prijateljstvo Close friendship
      5. Pobratenje Twin towns

      What stays home

      A town shows its linked towns only its public state: its buildings, its people, its age and today's weather. Never the learner's chat, mistakes, words or progress. Every request between towns is signed with the town's own key; an unlinked town gets nothing.

      A child's town

      A child's village is linked by a parent, on the machine, never from the child's phone. It takes no question with a link or an address in it, its tutor keeps every exchange age-appropriate, and the parent sees every question and answer.

      20:00 Janez pripoveduje zgodbo · Janez tells a story

      Zgodbe ob ognju Stories by the fire

      Every evening Stari Janez sits by the fire and tells a legend in chapters, at your level, and asks you along the way: Martin Krpan, Zlatorog, Kralj Matjaž, Peter Klepec. In the other villages it's Nonno Bepi, Opa Sepp and Old Wilf.

      Each story is written down in your notebook, »Moj zvezek zgodb«, in a hand-drawn style with pencil sketches taped in: every story you've heard, to read again, listen to, and be quizzed on.

      The story notebook's first page in handwriting on lined paper: Zapisano ob ognju, written down by the fire, and its contents: Zlatorog, Kralj Matjaž, Martin Krpan, with dates.
      A notebook page of Zlatorog: lines of the story in blue ink, and a pencil sketch taped in of the white fairies and the golden-horned chamois under the mountains.

      Zlatorog, beli gams z zlatimi rogovi.

      Zlatorog, the white chamois with golden horns.

      21:00 Teta Ančka posluša radio · Aunt Ančka listens to the radio

      Učitelj The tutor

      Behind the app runs a Claude Code session on your machine: your tutor. The app's chat goes straight to it. It knows what you got wrong yesterday, answers about any exercise, and builds the content as you progress:

      • new dialogs, scenes and villagers' lines, at your level
      • evening stories and grammar pages
      • word packs and practice modules for your weak spots
      • fixes for anything you report as wrong, with what it cost you given back

      It publishes them to the app through the bridge's MCP tools, and the phone shows them at once. In the chat you can bookmark an answer, reply to a message from last week, or look things up in the archive.

      The tutor's skills grew from m98/fluent, the AI language learning kit for Claude Code. It also works on its own, in the terminal.

      Tvoj učitelj · Your tutor example

      About: »Dober večer! Sedite, sedite.«

      Zakaj »sedite« in ne »sedi«?

      Sedite is the vi form: Babica is talking to several of you, or politely to one. To one friend it's sedi, as you told Luka this morning.

      Both are sesti, to sit down. Sitting there already is sedeti: Babica sedi pri ognju.

      📌 Bookmarked↩︎ Reply

      New in the village: a short drill on ti and vi for tomorrow.

      22:00 Luka je na straži · Luka is on watch

      Kako deluje How it works

      How Lani fits together The Android app talks to the bridge over HTTP and server-sent events, through your tailnet. The bridge, a Bun program on your machine, keeps your data as JSON files there and talks to your Claude Code session, the tutor, over an MCP channel. The tutor publishes dialogs, stories, grammar pages and modules back through the bridge to the app. your machine 📱 Android app Kotlin, Compose village · scenes reviews · chat 🌉 Bridge Bun, TypeScript serves the app MCP tools 🧑‍🏫 Claude Code your tutor session skills · hooks writes content your data (JSON, git) HTTP · SSE tailnet MCP channel How Lani fits together: the app talks to the bridge over HTTP and SSE through your tailnet; on your machine the bridge keeps your data and talks to the Claude Code tutor over MCP. 📱 Android app village · scenes · chat HTTP · SSE tailnet your machine 🌉 Bridge Bun · MCP tools your data MCP channel 🧑‍🏫 Claude Code your tutor · skills · hooks

      companion/android/

      The app, in Kotlin and Jetpack Compose. The village, the scenes and the people are drawn in code.

      companion/bridge/

      Serves the app, keeps your data (progress, mistakes, reviews, the village) as JSON on your machine, in a git repository of its own, and lets the tutor publish content.

      companion/cultures/ · scenes/ · grammar/

      The villages and their people, the scenes and stories, the grammar pages: content anyone can read and correct.

      .claude/

      The tutor's skills and hooks. LEARNING_SYSTEM.md is its method: active recall, SM-2, immediate feedback.

      22:45 Nejc ne more spati · Nejc can't sleep

      Na svojem računalniku Run it yourself

      Lani runs self-hosted today: the bridge and the tutor on a machine of yours that stays on (Linux or macOS), the app on your Android phone. There is no hosted version and no store release. You need Claude Code with a Claude plan or API key, Bun and an Android phone.

      1. Get Lani and run the setup wizard: the learner, their data, voices, the network, pairing

        git clone https://github.com/fentas/lani.git && cd lani
        companion/bin/lani-setup
      2. Start your tutor (tmux; detach with Ctrl-b d)

        companion/bin/lani-session
      3. Build the app (JDK 21 and the Android SDK) and install it

        cd companion/android && ./gradlew :app:assembleRelease
        adb install -r app/build/outputs/apk/release/app-release.apk
      4. Pair the phone: scan the QR code in the app

        companion/bin/lani-pair

      The data stays on your machine, in a git repository of its own, committed after each session. The guide, and every step by hand: docs/setup.md; what leaves your machine: docs/privacy.md; the rest (Tailscale, voices, speech recognition, the bridge as a service, backups): companion/README.md.

      23:30 Sova se oglaša · An owl is calling

      Odprta koda Open source

      Lani is free software under the GNU Affero General Public License 3.0 or later. It began as a fork of m98/fluent by Mohammad Kermani and the Fluent contributors (MIT); the parts from it stay available under MIT as well.

      Corrections to the Slovene are especially welcome: much of the content is machine-written and marked so until a native speaker has read it. The same goes for this site's Slovene, German and Italian. See CONTRIBUTING.md.

      Credits

      Dictionary
      Wiktionary via kaikki.org, CC BY-SA 4.0
      Notebook's handwriting
      Kalam by the Indian Type Foundry, SIL Open Font License 1.1
      Ambient sounds
      Synthesized in code, CC0 1.0
      Pixel art
      Drawn by code in the app, part of the program
      This site's fonts
      Pixelify Sans, Nunito and Kalam, SIL OFL 1.1

      Details in NOTICE.md.