-
-
Ask it to explain prime-checking code — get working Python, an English breakdown, and a real Amharic translation. Fully offline, no signal.
-
Interactive mode: chat directly with the assistant and get structured code patches back — no restart, no reload, just ask and build.
-
Point it at real code — it reads the function via a dependency graph, then returns a programatically structured fix as JSON. No guessing.
-
under the hood "See exactly what the model sees — full source for the target function, only signatures for its dependencies. No black box.
-
Tutor mode, a different language — Hausa this time. Code, English explanation, and a genuine Hausa translation, all offline.
-
SWAHILI — a full Flask CRUD API, five endpoints deep, generated locally in one pass. No cloud, no copy-pasting from docs
-
SWAHILI — a full Flask CRUD API, five endpoints deep, generated locally in one pass. No cloud, no copy-pasting from docs
Story
Inspiration
We studied computer science in Eritrea, where a working outlet and a working internet connection were never things we could take for granted at the same time. To reach a cyber café with a connection worth paying for, we traveled kilometers — and even then, the connection barely held, dropping mid-download, mid-search, mid-thought.
We remember debugging an Android app for days over something that would take a working developer minutes to resolve. Stranded without a stable connection, we turned to what the library had: a copy of Java in a Nutshell (David Flanagan, 1996) — a book older than the JDK versions and Android APIs we were actually working with. It described a language that no longer quite existed. We sat with the gap between what the book knew and what our code needed, and tried to bridge it by instinct.
That gap is the real story here — not a lack of ability, but a lack of access. Frameworks and tools move fast; electricity and bandwidth do not move at all where we were. A model that could sit on a modest laptop and simply know things — no signal required — would have saved us days we never got back.
What We Learned
We don't need the cloud to belong in the AI race.
Low-income regions of Africa are treated as consumers of technology built elsewhere, for elsewhere's infrastructure. But intelligence that lives entirely on-device — no API call, no subscription, no signal — doesn't ask permission from a power grid or a fiber line. It can sit in a household the same way a radio does: something you own outright, that works because you have it, not because someone far away kept a server running.
That's the shift. Not "AI, but smaller." AI that was never waiting on a connection to begin with. And reaching that household couldn't stop at one language, either — offline intelligence that only speaks English still leaves out most of the continent it's meant to serve.
How We Built It
We started from the constraint, not the ambition: everything had to run, fully, on a single modest laptop — no network calls, no fallback to a server somewhere.
The model. We use Qwen2.5-Coder-1.5B-Instruct, quantized to GGUF Q5_K_M and served through llama.cpp. Quantization research from the GGUF/K-quant community made this possible in the first place — compressing each weight from 32 bits down to roughly \( 5.5 \) bits, trading a small, carefully measured amount of precision for a footprint small enough to actually fit:
$$ \text{Size}_{\text{fp32}} \approx 1.78\times10^{9} \times 4\text{ bytes} \approx 7.1\text{ GB} $$
$$ \text{Size}_{\text{Q5_K_M}} \approx 1.78\times10^{9} \times \frac{5.5\text{ bits}}{8} \approx 1.2\text{ GB} $$
Roughly a sixth of the size, on disk and in memory, for a model that still writes working code.
The context engine. Around the model, we built what we call a DS-Code Graph — a lightweight dependency graph of a codebase, built from real IMPORT, CONTAIN, and CALL relationships rather than just handing the model a whole file. It's a small, direct application of an old idea from software engineering: program dependence and call-graph analysis, used here to pull in only the function being debugged and the handful of things it actually touches — signatures and docstrings for its neighbors, full source for the target itself. A model this size doesn't have room to waste tokens on code that isn't relevant; the graph makes sure it doesn't have to.
Structured output. To keep the model honest about its output format, we constrained generation with a grammar — the model is not free to ramble; it must return a structured patch, every time:
{
"file_path": "app/DataProcessor.java",
"action": "fix",
"code_patch": "..."
}
Grammar-constrained decoding turns a small model's biggest weakness — inconsistency — into a non-issue, because the shape of the answer is no longer something it has to get right on its own.
The language layer. The last piece came from a discovery, not a plan: this model, on its own, could not reliably write in Swahili, Amharic, or the other regional languages we wanted it to teach in — it would quietly fall back to English or lose coherence entirely. Rather than force it, we brought in a second, dedicated model for that job alone: Meta's NLLB-200, research built specifically so that low-resource languages are not the ones left behind when translation technology improves. It felt fitting — a project born from being on the wrong side of a resource gap, built in part on research whose entire premise is closing one.
We didn't stop at one regional language. The tutor mode now speaks eight — Swahili, Amharic, Tigrinya, Arabic, Hausa, Yoruba, Igbo, and Zulu — spanning East, West, North, and Southern Africa, and covering several of the continent's most widely spoken languages by native speaker count. None of them were picked by assumption. We benchmarked NLLB's own published per-language translation-quality scores before deciding what to include, so the accuracy behind "multilingual" is a measured, engineered property of the translation layer itself — not a hope that one generalist model would happen to be equally fluent in eight languages at once.
The two models never load at once. One finishes and steps aside before the other begins, so memory never has to hold both.
Challenges The single hardest constraint was the ceiling itself: 8 GB of RAM, with a working budget of
RAM peak ≤ 7 GB RAM peak ≤7 GB to leave room for the operating system around it. The genuinely capable models — the ones that make debugging effortless — start well above that line. We couldn't reach for them, no matter how much we wanted to.
So the real work became finding the smallest model that still refused to fail at the job. We tested down through several sizes and quantization levels, watching capability drop long before we expected it to — a smaller model doesn't fail loudly, it fails quietly, returning something that looks like an answer but isn't one. Finding the floor — the smallest footprint that still produced correct, trustworthy code — took longer than building the pipeline around it.
The same tension showed up again in the language layer: the model that fit the memory budget was not the model that could speak Tigrinya or Amharic on its own. Solving that meant accepting that one model doing everything was the wrong goal — two small, focused tools, handing off to each other cleanly, could do what one compromised generalist couldn't.
Every constraint in this project traces back to the same place we started: a room without power, a connection that barely held, and a book that was thirty years too old. We built this so that the next person in that room doesn't have to wait for either.

Log in or sign up for Devpost to join the conversation.