DEV Community

Cover image for I Built Kalaam: An Arabic Tutor Whose UI Gemini Assembles at Runtime
Sayed Ali Alkamel
Sayed Ali Alkamel

Posted on

I Built Kalaam: An Arabic Tutor Whose UI Gemini Assembles at Runtime

TL;DR

  • What it is: Kalaam is an open-source Flutter app where a Gemini model composes each Arabic lesson screen at runtime from a combined catalog of 13 custom Arabic widgets and 14 genui SDK primitives. No fixed screens. No hardcoded lesson flow.
  • Who it is for: Flutter developers building AI-native apps who want a real, runnable reference implementation, not another chatbot wrapper.
  • Run it now (no Firebase, no API key, ~30 seconds):
  git clone https://github.com/sayed3li97/kalaam.git
  cd kalaam && flutter pub get
  dart run build_runner build --delete-conflicting-outputs
  flutter run --dart-define=KALAAM_DEMO=true
  • Full source: https://github.com/sayed3li97/kalaam
  • Maturity: Alpha. Demo Mode is stable. Live Mode (Gemini calling your Firebase project in real time) requires a setup step documented in the README.

Table of Contents


Arabic morphology operates on a principle with no real equivalent in English. Almost every word in the language descends from a three-letter root through predictable morphological patterns. The root ك-ت-ب (k-t-b, the concept of writing) produces كَتَبَ (he wrote), كِتَاب (book), كَاتِب (writer), مَكْتَب (office), مَكْتُوب (written). Classical Arab grammarians built complete transformation tables for these patterns. Modern linguists write dissertations about them. The system is elegant, generative, and genuinely hard to teach with a flashcard.

Every Arabic learning app I have reviewed responds to this complexity the same way: fixed screens, hardcoded vocabulary lists, a multiple-choice grid that never changes shape, and a next button the AI model has no opinion about. The model, when it appears at all, generates text that lands in a Text widget inside a layout the developer wired months before knowing what the learner would need. The interface is not part of what the model controls.

Kalaam takes a different position. Rather than asking a language model to fill in a predetermined form, Kalaam gives Gemini a catalog of real Flutter widgets and lets it decide what to compose. The model reads a JSON schema describing 13 custom Arabic teaching widgets plus 14 genui built-in primitives, then streams an A2UI surface that the GenUI SDK materializes into an actual widget tree on the device. Tap a word node in the root diagram, and the interaction goes back to Gemini as a UserActionEvent. The model then writes whatever surface comes next.


What Problem This Actually Solves

The standard architecture for AI-assisted Flutter apps produces code that looks like this:

// What most "AI-powered" learning apps actually do
final response = await model.generateContent([Content.text(prompt)]);
return Text(response.text ?? '');
Enter fullscreen mode Exit fullscreen mode

The model generates text. A fixed UI the developer designed wraps it. The model has no knowledge of what a conjugation table looks like, cannot decide to show a vocabulary carousel instead of a fill-in-the-blank when the learner already knows the words, and cannot react to a tapped word by composing a triliteral root diagram for that specific word. Every state transition was decided at compile time.

The architectural gap: A model that only fills Strings into fixed widgets can generate better content. It cannot generate better teaching. Those are different things.

The genui Flutter package (A2UI v0.9) addresses this by giving the model a catalog schema and a structured transport protocol. The model emits JSON messages like createSurface and updateComponents that describe a widget tree using catalog item names. The SDK parses those messages and calls each widget's registered widgetBuilder. The developer defines the catalog. The model decides which items to use, with what data, and in what order.

Kalaam is a complete, open-source implementation of this pattern for Arabic instruction, with 13 custom CatalogItem widgets covering morphology, vocabulary, phonetics, dialogue, cultural context, and progress tracking. The full source is at https://github.com/sayed3li97/kalaam.


What Kalaam Is

Kalaam is a Flutter application where Gemini assembles each Arabic lesson interface at runtime. Pick a scenario (Ordering Coffee, a Cairo market negotiation, a formal business letter), and the model composes a lesson surface: a scene-setter first, then vocabulary cards, a triliteral root diagram, a conjugation table, a quiz, depending on what the learner does and how they answer. The widget sequence is not scripted. The model chooses it.

Kalaam home screen — scenario picker with streak badges
  
Root System diagram — Arabic triliteral root ش-ر-ب with radial word family
  
Root node expanded — wazn pattern badge and Explore button

Scenario picker  ·  Root System (ش-ر-ب)  ·  Tap a node to reveal its morphological pattern — every screen composed live by Gemini.

I (Sayed Ali Alkamel, @sayed3li97) made one architectural decision early that shaped everything else: representing the entire model-facing contract as typed Dart CatalogItem objects rather than a YAML configuration file or a JSON registry. The dataSchema and widgetBuilder on each item live in the same Dart file. The JSON schema the model learns and the Flutter code that renders it are co-located. If you change the schema, the compiler tells you if the widget no longer matches it.

Install and run in Demo Mode (Flutter 3.44+, no Firebase, no API key needed):

git clone https://github.com/sayed3li97/kalaam.git
cd kalaam
flutter pub get
dart run build_runner build --delete-conflicting-outputs
flutter run --dart-define=KALAAM_DEMO=true
Enter fullscreen mode Exit fullscreen mode

The core primitive is CatalogItem. Every custom widget Kalaam exposes to the model is registered as one. Here is the RootExplorer registration, simplified:

final rootExplorerItem = CatalogItem(
  name: 'RootExplorer',
  dataSchema: S.object(
    properties: {
      'rootWord': S.string(
        description: 'Triliteral root, letters joined by dashes, e.g. ك-ت-ب',
      ),
      'rootMeaning': S.string(description: 'Core meaning of the root in English'),
      'family': S.list(
        description: 'Derived words that share this root',
        items: S.object(properties: {
          'word': S.string(description: 'Derived word with full harakat'),
          'transliteration': S.string(description: 'Romanised pronunciation'),
          'meaning': S.string(description: 'English meaning'),
          'pattern': S.string(description: 'Morphological wazn, e.g. مَفْعُول'),
          'isExpanded': S.boolean(description: 'DataModel-bound, false initially'),
        }),
      ),
    },
    required: ['rootWord', 'rootMeaning', 'family'],
  ),
  widgetBuilder: (ctx) {
    final data = ctx.data as Map<String, Object?>;
    return _RootExplorerWidget(
      rootWord: data['rootWord'] as String? ?? '',
      family: data['family'] as List<dynamic>? ?? [],
      ctx: ctx,
    );
  },
);
Enter fullscreen mode Exit fullscreen mode

When Gemini wants to teach the ش-ر-ب root family, it emits a createSurface message containing a RootExplorer component with the root letters, meaning, and word family filled in. The GenUI SDK calls widgetBuilder and returns a live Flutter widget. The model never saw the Flutter code. It only knew the JSON schema.

Under the hood, a SurfaceController manages the bidirectional loop. Incoming A2UI messages build the current surface. Outgoing UserActionEvent payloads carry learner interactions back into the model's conversation history, closing the loop for the next turn.


Key Features in Depth

The Root System Explorer

The RootExplorer renders a radial diagram centered on a triliteral root. Each satellite node is a derived word in the root family. Tapping a node expands it from a 92×46pt pill showing just the Arabic word to a 155×144pt card revealing the morphological pattern (وزن / wazn), the transliteration and English meaning, and an "Explore" button.

Root Explorer — مَشْرُوب node expanded with وزن مَفْعُول badge and Explore button

Tapping مَشْرُوب (a drink) expands the node to reveal its wazn (وزن مَفْعُول), transliteration, English meaning, and the Explore→ button that branches into a new Gemini-composed surface.

That Explore button is not cosmetic. It dispatches a UserActionEvent back to Gemini:

sendKalaamAction(ctx, 'explore_word', {
  'word': word,
  'root': rootWord,
  'meaning': meaning,
});
Enter fullscreen mode Exit fullscreen mode

Gemini receives this in the next conversation turn and can compose an entirely new surface for that specific word: a VocabCard with its etymology, a ConjugationTable if it is a verb, a CulturalNote if the word has idiomatic significance. The diagram is not a static illustration. It is a branch point in the lesson.

HarakatBuilder

Arabic diacritics (harakat) are one of the most common barriers for intermediate learners, and also one of the hardest to teach with a flashcard. Most learning apps just display fully voweled text. HarakatBuilder inverts the exercise.

Given a consonant skeleton and a target vocalization, the learner taps each letter and selects a diacritic from a palette: fatha (َ), kasra (ِ), damma (ُ), sukun (ْ), shadda (ّ). The word re-renders with each placed diacritic in real time. On correct completion, the widget dispatches:

sendKalaamAction(ctx, 'completed', {'isCorrect': true});
Enter fullscreen mode Exit fullscreen mode

The model receives that and composes the next step based on what the learner just demonstrated they know. No hardcoded branching logic in the Flutter code. The model decides where to go.

Live GenUI Inspector

The Inspector is the piece of Kalaam that surprises developers most on first run.

A {} button in the session screen's app bar opens a slide-up panel that shows every A2UI message Gemini has emitted during the current session, newest last, pretty-printed as JSON. You can watch createSurface messages appear as the lesson loads. You can see the component names, the data the model chose to fill in, the surface IDs. You can trace exactly what JSON produced exactly what widget on screen.

When I first built this, I left the Inspector open for every demo I ran internally. Watching "component": "RootExplorer" appear in the stream, followed by a complete Arabic root family the model composed from nothing but the schema description, is the clearest explanation of what GenUI actually does. No architecture diagram I have drawn since has communicated it as well as this panel does in practice.

The Inspector is implemented as a ValueNotifier<List<String>> buffer on the transport layer, with a slide-up panel widget that rebuilds as messages arrive. It is not a debug-only feature: it stays in release builds because it is the most compelling demonstration of the pattern.

Live GenUI Inspector panel showing CREATE turn_2 A2UI JSON from Gemini

The GenUI Inspector open mid-session. The CREATE turn_2 badge marks a new surface creation message. Every field name and value was chosen by Gemini — no developer-written template produced this JSON.

Demo Mode

Live Mode requires a Firebase project with Gemini Developer API enabled. That setup step has a real cost for someone evaluating the project for the first time. Demo Mode removes it.

Run with --dart-define=KALAAM_DEMO=true and the app replays curated A2UI transcripts through the same A2uiTransportAdapter used in Live Mode. Nothing is mocked at the widget level. SurfaceController processes the same message types. CatalogItem widgetBuilder functions instantiate the same Flutter widgets. The difference is only the source of the A2UI stream: a scripted file instead of a live Gemini response.

This was not an accidental boundary. I put the swap at the transport layer deliberately so that Demo Mode exercises the real rendering pipeline. A bug in the catalog, a schema mismatch, an overflow in the Root Explorer: Demo Mode will surface all of them. It is not a polished preview mode. It is the actual system, running on prerecorded input.

VocabCarousel widget — Arabic word قَهْوَة with full harakat, transliteration, and definition

VocabCarousel showing قَهْوَة (coffee) with full diacritics, IPA, and example sentence — rendered from a Gemini-emitted VocabCarousel component in a Demo Mode replay.

The Combined Catalog

Kalaam's combined catalog gives the model 27 composable elements: 13 custom Arabic widgets plus 14 genui built-in primitives.

The 13 custom items: RootExplorer, HarakatBuilder, ConjugationTable, VocabCard, VocabCarousel, SceneCard, PhonemeCard, DialogueBubble, CulturalNote, MasteryRing, QuickChoice, SentenceBuilder, FillInTheBlank.

The 14 genui primitives: Column, Row, Card, Text, Button, Icon, Divider, Image, ChoicePicker, TextField, Slider, Tabs, List, AudioPlayer.

The model can compose both tiers freely. A Column containing a SceneCard, then a VocabCarousel, then a QuickChoice quiz is a perfectly valid A2UI surface. In practice, across Live Mode sessions I have run, the model reaches for mixed-tier layouts frequently: a Card primitive wrapping a custom DialogueBubble for roleplay, a Row of Button primitives alongside a MasteryRing. That mixing is where the showcase value sits.


How Kalaam Compares

Approach Model composes the layout Bidirectional events No-API-key demo Custom widget catalog Time to first running UI
Kalaam + GenUI SDK Yes Yes (UserActionEvent) Yes (Demo Mode) 27 items (13 custom + 14 primitives) ~30 seconds
DIY JSON-to-widget mapper Partial Manual implementation Depends You build it from scratch Weeks
flutter_ai_toolkit No (fixed chat UI) No Yes No ~1 hour
LLM + Text() widget No No Yes No ~10 minutes
Firebase Genkit + custom Flutter No Manual implementation No (requires Firebase) You build it from scratch Days to weeks

The flutter_ai_toolkit wins on time-to-working-chat: if you need a conversational UI embedded in an existing Flutter app, it is the fastest path by a significant margin. Use it. [INTERNAL LINK: flutter_ai_toolkit]

If you need the model to control the layout itself and not just the content inside a fixed layout, the DIY approach and Kalaam/GenUI are the two real options. Kalaam exists as a reference for what "DIY done well" looks like at meaningful scale, so you can evaluate whether using the SDK directly fits your use case before committing to building from scratch.


The Honest Objection

A senior Flutter developer who clones Kalaam and runs it in Demo Mode will ask one question almost immediately: "How much of this is Gemini and how much is a scripted replay?"

It is a fair question. Demo Mode replays prewritten A2UI transcripts. The Root Explorer diagram you see when you run flutter run --dart-define=KALAAM_DEMO=true was not composed by Gemini in real time. It was composed during development, reviewed, committed to the repo, and is being replayed now. The model is not in the loop in Demo Mode.

That is not a misleading presentation, but it matters for evaluating the system. Demo Mode does not show you how Gemini handles unexpected learner input. It does not show what happens when the model emits a structurally valid but semantically off A2UI message (the GenUI SDK renders a graceful error card). It does not show live response latency.

Live Mode is where those questions get real answers. It also requires real setup: a Firebase project, Gemini Developer API enabled, Firebase App Check configured, and a billing budget alert set. The README's "Option B" section walks through all of it.

The limitation I want to name clearly: Kalaam's Live Mode prompt engineering is functional but not complete. In live sessions, Gemini occasionally reaches for a VocabCard where a RootExplorer would have been more instructive, or composes a layout that works but underuses the available screen space. The catalog gives the model the right tools. Teaching it when to reach for each one is an ongoing prompt engineering problem with no fully correct solution yet.

This is alpha software. The architecture is the part that works well. The prompt, the few-shot examples, and the handling of edge-case model outputs are the areas where contributions move the project most.


Getting Started in Under 5 Minutes

Requirements: Flutter 3.44+, Dart 3.9+, a connected device or simulator.

Step 1: Clone and install dependencies

git clone https://github.com/sayed3li97/kalaam.git
cd kalaam
flutter pub get
dart run build_runner build --delete-conflicting-outputs
Enter fullscreen mode Exit fullscreen mode

Step 2: Run in Demo Mode

flutter run --dart-define=KALAAM_DEMO=true
Enter fullscreen mode Exit fullscreen mode

No Firebase project. No Gemini API key. No account required. The demo replays an Ordering Coffee lesson through the real GenUI pipeline.

Step 3: Open the Inspector

Once a lesson starts, tap the {} button in the top-right of the session screen. The GenUI Inspector panel opens and shows every A2UI message the surface was built from. This is where the architecture becomes visible.

Step 4 (optional): Switch to Live Mode

Create a Firebase project at console.firebase.google.com. Enable Build → AI Logic → Get started → Gemini Developer API (free tier available). Then:

dart pub global activate flutterfire_cli
flutterfire configure    # generates lib/firebase_options.dart, which is git-ignored
flutter run              # no --dart-define flag; live mode is the default
Enter fullscreen mode Exit fullscreen mode

Set a billing budget alert before running live sessions. The Gemini Developer API bills your Firebase project, and firebase_options.dart contains credentials that should never be committed to a public repository. The .gitignore in Kalaam already excludes it, along with google-services.json and GoogleService-Info.plist. Only *.example templates are tracked.

Known open issues (as of the initial open-source release):

  • Occasional layout overflow on very long Arabic words in VocabCard on narrow screens.
  • ConjugationTable scroll behavior on small-screen Android devices.
  • Live Mode system prompt does not yet handle learner dialect preference (MSA only).

How to Contribute

Kalaam is open source under Apache 2.0 and genuinely looking for people to use it, break it, and tell me what they found.

Running Demo Mode and filing a GitHub issue when something looks wrong, visually off, or surprising is a real contribution. You do not need to write code.

Where contributions have the highest impact right now:

Prompt refinement is the single highest-leverage area. The system prompt lives in lib/features/session/prompt/. If you have experience with Arabic pedagogy or prompt engineering for Gemini, adding one well-structured example to the few-shots can change what the model reaches for across an entire session. The current few-shot coverage is thin.

New catalog items follow a clear pattern. The reference implementation is lib/features/session/catalog/items/scene_card_item.dart. Every CatalogItem needs a dataSchema, exampleData, and a widgetBuilder. Register it in catalog.dart and add a fixture in test/kalaam_catalog_test.dart. The test infrastructure is already there; you just fill in the new widget's test case.

Platform testing is something I cannot do alone. Kalaam has CI for iOS, Android, and web. Arabic text rendering behavior varies across platform versions and font configurations in ways that are hard to predict. If you run into something that looks wrong on a specific device or OS version, filing an issue with a screenshot is directly useful.

Good first issues are labeled on GitHub. They are scoped to single files and documented with enough context to start without knowing the whole codebase.

Full process: CONTRIBUTING.md.


What This Means for Flutter Development

Three practical framings depending on where you are right now:

If you are currently building AI features by wiring an LLM to a Text widget, Kalaam is a working example of what the next step looks like architecturally. The migration is not trivial (you need to define a catalog, think in surfaces rather than screens, and design the bidirectional event contract), but the reference implementation now exists.

If you are evaluating GenUI for production use, Kalaam gives you 13 CatalogItem implementations to read and adapt. The bidirectional event system in sendKalaamAction, the data model binding in BoundBool and BoundString, the Inspector widget, and the Demo Mode scaffold are all things you can extract and use in your own project.

If you are teaching Flutter architecture or developer experience, the Inspector is a classroom tool worth having. Watching A2UI JSON tokens resolve into typed Flutter widgets in real time, in an app you cloned ten minutes ago, communicates what "model-driven UI" actually means better than any diagram I know.

One concrete recommendation before building a custom JSON-to-widget mapper for your own AI-native Flutter project: read the genui package README and the A2UI v0.9 specification alongside Kalaam's catalog. The scaffold may be closer to complete than you expect.


Questions developers are actually asking about Kalaam

Is Kalaam production-ready as an Arabic learning app?

No. Kalaam is an open-source showcase application in alpha, designed to demonstrate GenUI architecture patterns for Flutter developers. The widget catalog is functional, the Demo Mode is stable, and the GenUI bidirectional loop works end-to-end. The Arabic pedagogy, prompt engineering, and learner progress tracking are not at production quality. If you are building a production Arabic learning product, Kalaam's catalog and architecture are worth studying and adapting, but the app itself is a starting point, not a finished product.

What is the difference between Kalaam's Demo Mode and Live Mode?

Demo Mode (--dart-define=KALAAM_DEMO=true) replays prerecorded A2UI transcripts through the real GenUI pipeline. No API key or Firebase project is needed. Live Mode calls Gemini through Firebase AI Logic in real time, composing each lesson surface fresh based on the learner's actions and conversation history. Demo Mode is fully stable and exercises the same rendering code as Live Mode. Live Mode is functional but requires Firebase setup and is billed through your Firebase project's Gemini Developer API quota.

Does Kalaam require a paid Gemini API key?

In Demo Mode, no. In Live Mode, Kalaam uses Firebase AI Logic with the Gemini Developer API, which has a free tier but can incur charges at scale. The README recommends setting a Firebase billing budget alert before enabling Live Mode. Firebase App Check is also required to prevent unauthorized API usage, since the Gemini Developer API endpoint bills your project and an unprotected key is abusable.

How does Kalaam's approach differ from using flutter_ai_toolkit?

The flutter_ai_toolkit (Google) embeds a ready-made chat UI component into an existing Flutter app. The model generates text responses inside a conversation interface the toolkit provides. Kalaam's GenUI approach is architecturally different: the model decides what Flutter widgets to render, which ones to compose together, and how to lay them out. The developer provides a widget catalog; the model chooses from it at runtime and updates surfaces in place. These are tools for different problems, not competing approaches to the same one.

Can I add my own widgets to Kalaam's catalog?

Yes. Every item in the catalog is a CatalogItem with three required fields: a dataSchema (the JSON Schema object the model uses to understand what data the widget accepts), exampleData (a worked example the system prompt includes as a few-shot), and a widgetBuilder (a function taking CatalogItemContext and returning a Flutter Widget). The reference implementation is lib/features/session/catalog/items/scene_card_item.dart. Register your item in lib/features/session/catalog/catalog.dart and add a fixture test in test/kalaam_catalog_test.dart.

What version of Flutter does Kalaam require, and why?

Flutter 3.44+ and Dart 3.9+. The lower bound comes from the genui package's dependency requirements and Kalaam's use of Dart 3 patterns: @riverpod codegen, @freezed immutable models, and sealed classes. The codegen step (dart run build_runner build) must complete before running the app; generated files are not committed to the repository.


What Comes Next

The roadmap items below are drawn from open GitHub issues and gaps I identified during development. None have committed dates.

Prompt few-shot expansion is the highest-priority item. The current system prompt covers the Ordering Coffee scenario in detail. More worked examples from different lesson contexts (market negotiation, formal letter writing, phonetics drill) would each give the model a better map for when to reach for each catalog widget. A single well-structured example in the few-shots has outsized effect on Live Mode output quality.

Learner profile binding is the next feature in the data model. The /learner/ path in the DataModel already exists (tracking words seen, accuracy, weak phonemes, streak). The model reads it at session start. The missing piece is writing it after each completed interaction and binding MasteryRing to real accumulated progress rather than per-session state.

Dialect support is on the wishlist. Modern Standard Arabic is the current default. A dialect selector that modifies the system prompt would let the app serve Gulf Arabic, Egyptian Arabic, and Levantine Arabic learners, each of which has distinct vocabulary and morphological patterns.

Better malformed A2UI handling is a known gap. When Gemini emits a structurally valid but semantically incorrect A2UI message (wrong component name, missing required field), the current behavior is a generic error card. Partial rendering and schema-level error recovery would make Live Mode more resilient.


The Catalog Is the New Source of Truth

There is a pattern in software where the interface between two systems starts as an implementation detail and gradually becomes the most load-bearing thing in the architecture. REST APIs replaced direct database calls. GraphQL schemas replaced hand-written REST endpoints. Type systems replaced runtime duck typing. In each case, the contract became the artifact worth designing carefully.

Kalaam's CatalogItem plays this role between a language model and a Flutter widget tree. The dataSchema property is what the model learns. It is the description Gemini uses to decide when to emit a RootExplorer versus a ConjugationTable, what fields to fill in, what data shapes are valid. The schema is how you teach a model what your widgets can do.

The practical consequence: time spent making catalog schemas precise pays forward across every session where the model uses that widget. A vague description field on a schema property produces vague model output. A specific description, one that names the format and gives a concrete example, produces surfaces that feel like they were composed for the learner's exact situation, because the model had enough information to make a real choice.

I built Kalaam to see what Arabic instruction looks like when the interface is part of what the model controls. The answer: it looks different every session, reaches for a triliteral root diagram when that is the right tool, and reacts to a learner tapping a specific word in ways a static screen cannot. That sounds obvious in retrospect. It is harder to build correctly than it appears.

The source is at https://github.com/sayed3li97/kalaam. Run it, open the Inspector, tap a word in the root diagram, and watch what the model composes next. Something in there is worth knowing about.


References

  1. Kalaam GitHub repository: https://github.com/sayed3li97/kalaam
  2. genui Flutter package (pub.dev): https://pub.dev/packages/genui
  3. A2UI v0.9 protocol (Google): https://github.com/google/A2UI
  4. Firebase AI Logic (Gemini Developer API): https://firebase.google.com/docs/ai-logic
  5. Firebase App Check: https://firebase.google.com/docs/app-check
  6. flutter_ai_toolkit (Google, pub.dev): https://pub.dev/packages/flutter_ai_toolkit
  7. Flutter 3.44 release notes: https://docs.flutter.dev/release/release-notes
  8. Riverpod state management (pub.dev): https://pub.dev/packages/riverpod
  9. Freezed package (pub.dev): https://pub.dev/packages/freezed
  10. build_runner (pub.dev): https://pub.dev/packages/build_runner
  11. Amiri Arabic font: https://github.com/alif-type/amiri
  12. IBM Plex Arabic font: https://github.com/IBM/plex
  13. flutterfire CLI: https://firebase.flutter.dev/docs/cli

About the Author

Sayed Ali Alkamel is a Google Developer Expert in Dart and Flutter, co-founder of Flutter MENA, and Manager of Digital Application Platforms at Oman Housing Bank. He has spoken at tech events across 22+ countries and shipped apps with 2.5M+ downloads. He writes about Flutter, AI, and the developer experience at dev.to/sayed_ali_alkamel.

Top comments (0)