<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vrushali</title>
    <description>The latest articles on DEV Community by Vrushali (@vrushali_dev_15).</description>
    <link>https://dev.to/vrushali_dev_15</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3296637%2F367e5386-7941-4c96-ad7b-d5bf2de23c7d.png</url>
      <title>DEV Community: Vrushali</title>
      <link>https://dev.to/vrushali_dev_15</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vrushali_dev_15"/>
    <language>en</language>
    <item>
      <title>Stitch Desk is a local-first order assistant for boutiques and tailors.</title>
      <dc:creator>Vrushali</dc:creator>
      <pubDate>Wed, 14 Oct 2026 14:10:51 +0000</pubDate>
      <link>https://dev.to/vrushali_dev_15/stitch-desk-is-a-local-first-order-assistant-for-boutiques-and-tailors-2gk0</link>
      <guid>https://dev.to/vrushali_dev_15/stitch-desk-is-a-local-first-order-assistant-for-boutiques-and-tailors-2gk0</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Stitch Desk&lt;/strong&gt; is a local-first order assistant for boutiques and tailors.&lt;/p&gt;

&lt;p&gt;Many small tailoring shops still run on paper notebooks, loose receipts, and WhatsApp chats. A customer's measurements are in one place, the delivery date is on a sticky note, and the balance is in the owner's head. In busy seasons, that is where orders get lost and deliveries get late.&lt;/p&gt;

&lt;p&gt;Stitch Desk turns that into one small app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Note to order card:&lt;/strong&gt; The owner types or pastes a messy note, like &lt;em&gt;"Anna, bridal lehenga, boat neck blouse, deep U back, bust 36, waist 30, delivery 20 Nov, total 24000, advance 10000"&lt;/em&gt;. A local AI model turns it into an editable card with the customer, garment, design notes, measurements, delivery date, total, advance, and balance. The owner checks it before saving.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orders board:&lt;/strong&gt; Orders sorted by delivery date, with status chips (New, Stitching, Trial pending, Ready, Delivered), a "due this week" count, and the total balance still pending.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customers:&lt;/strong&gt; Orders grouped by customer, with a saved phone number, the latest measurements for each garment, and order history.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WhatsApp message drafts:&lt;/strong&gt; "Ready for trial", "Order ready", and "Balance reminder" messages the owner can edit and open in WhatsApp.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design search:&lt;/strong&gt; The owner describes an outfit ("bridal lehenga blouse, boat neck, deep back"), sees matching pictures, and links up to three as references on an order.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Who would pay for it:&lt;/strong&gt; small boutiques and tailors who keep orders and measurements in notebooks and chats, and who lose time (and sometimes money) chasing details and balances. I have not set a price. I describe below what a tailor said when I showed it to them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Screenshots:&lt;/strong&gt; 
## Demo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn77vsglrml395hj5tvp9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn77vsglrml395hj5tvp9.png" alt="Stitch Desk orders board view showing status chips and delivery dates" width="780" height="2204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2bzi9eywjatej3kwo2ak.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2bzi9eywjatej3kwo2ak.png" alt="Customer profile screen showing measurement history and saved details" width="780" height="3400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fexusmida84zn895l2u6c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fexusmida84zn895l2u6c.png" alt="Design search interface with matching visual references" width="780" height="3556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fod49fl6gha2b3msob04u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fod49fl6gha2b3msob04u.png" alt="Order card creation view populated via local AI model" width="780" height="3088"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;All screenshots use fictional sample data. The banner is an AI-generated illustration.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/vrush1588" rel="noopener noreferrer"&gt;
        vrush1588
      &lt;/a&gt; / &lt;a href="https://github.com/vrush1588/stitch-desk" rel="noopener noreferrer"&gt;
        stitch-desk
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A local-first order assistant for boutiques and tailors. Turn customer notes into editable order cards, organize contact details and measurements, draft WhatsApp messages, and find outfit design images for order references.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Stitch Desk&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Stitch Desk is a local-first order assistant for boutiques and tailors: turn a messy customer note into an editable order card, keep customer contact details and measurements together with WhatsApp message drafts, and search for outfit design pictures to link as order references.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Create order cards from a pasted note with local AI, or fill the order in by hand.&lt;/li&gt;
&lt;li&gt;Track delivery dates, order status, advances, balances, and design references.&lt;/li&gt;
&lt;li&gt;Group saved orders by customer, save contact numbers and measurements, and create editable WhatsApp message drafts.&lt;/li&gt;
&lt;li&gt;Search Google Images through SerpApi and attach up to three linked design references to an order.&lt;/li&gt;
&lt;li&gt;Keep orders, customer details, and in-progress order drafts in this browser's local storage.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Who it's for&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Stitch Desk is for small boutiques and tailors who keep orders, measurements, and delivery dates in notebooks and WhatsApp chats. They get a quick way to turn a spoken…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/vrush1588/stitch-desk" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The repo has a README, setup steps, an MIT license, and an &lt;code&gt;.env.example&lt;/code&gt; with no secrets.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Stack:&lt;/strong&gt; React + Vite for the app, a small Node + Express server for design search, Ollama running &lt;strong&gt;Gemma (&lt;code&gt;gemma3:4b&lt;/code&gt;)&lt;/strong&gt; on my own laptop, SerpApi for image search, and the browser's &lt;code&gt;localStorage&lt;/code&gt; for orders and customers. I built it one feature at a time with GitHub Copilot prompts, and committed after each step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where Gemma is used (three jobs):&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Order cards.&lt;/strong&gt; The app sends the owner's note and today's date to Gemma and asks for JSON only: customer, garment, design notes, measurements, delivery date, total, and advance. The prompt says never to invent values, and to leave a field empty if the note does not say it. The result is shown in an editable form with the label &lt;em&gt;"AI draft, please check"&lt;/em&gt;, and the balance is computed in code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Message wording.&lt;/strong&gt; The code builds each WhatsApp message from a fixed template with the customer's name, garment, delivery date, and balance. Gemma only rewrites it in a warmer tone. Then the code checks that every number and date from the template appears unchanged in Gemma's reply. If anything is missing or changed, the app uses the plain template instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search queries.&lt;/strong&gt; Gemma turns the owner's request into two short search phrases. The code then removes any phrase containing digits or a saved customer's name, so no private details reach the search service.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;SerpApi&lt;/strong&gt; runs the image search through my small server, so the API key never reaches the browser. Results are cached, so the same search never costs a second credit, and there is a per-session limit. The app saves only the thumbnail link, title, and source page for each reference, never the image itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If the model is off,&lt;/strong&gt; the app does not break. The order form becomes a manual form, and messages use the plain template.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I learned about using a small model for money-related data
&lt;/h3&gt;

&lt;p&gt;The biggest risk with an order app is a wrong number. A small model can misread or change figures, and a wrong balance in a message to a customer is a real problem. So I did not trust the model with anything that must be exact:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The balance is calculated in code, not by the model.&lt;/li&gt;
&lt;li&gt;The model never writes amounts or dates into messages. It only rewords around them, and the code verifies them.&lt;/li&gt;
&lt;li&gt;Every AI result is shown for the owner to edit before it is saved.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The cost stays near zero per order.&lt;/strong&gt; Gemma runs on the owner's own machine, so there is no per-note or per-message AI charge. For a small shop where each order brings in a small amount, a metered AI bill per card would eat into the margin. The only metered cost in my build is the optional image search, and I cache it to keep that low.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customer details stay on the device.&lt;/strong&gt; Names, phone numbers, and body measurements are sensitive. Notes and measurements are processed by a model on the owner's laptop and stored in the browser, and are not sent to a hosted AI service. Only short design-search phrases leave the machine, and the code removes names and digits from them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I could change how it behaves.&lt;/strong&gt; Because I control the prompts and the model setting, I could add strict rules (never invent values, keep numbers exactly as written) and swap the model by changing one setting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It is honest about limits.&lt;/strong&gt; Running the model myself made it clear what a 4B model can and cannot do. I describe the mistakes it made below and in the repo's README.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;I built Stitch Desk with GitHub Copilot's agent mode, using one prompt per feature and committing after each step so I could test it before moving on. I did not save a full session transcript, so here are the key prompts (shortened) and what I checked after each one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Base and layout&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Start from my existing React + Vite project, rename it "Stitch Desk", remove the old features, keep the Ollama connection, JSON parsing helpers, fallback pattern and localStorage utilities, and create a mobile-first layout with bottom navigation: Orders, New, Designs, Customers. Show a "Local AI on / off" badge.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Check:&lt;/em&gt; Four tabs render correctly, and the badge status updates instantly when stopping or starting Ollama.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Note to order card (the core feature)&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Send the owner's note and today's date to the local Gemma model and ask for JSON only (customer, garment, design notes, measurements, delivery date, total, advance). Never invent values, use null for anything missing, keep numbers exactly as written. Show an editable form labelled "AI draft, please check" with the balance computed in code. If Ollama is off, show an empty manual form.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Check:&lt;/em&gt; I tested 5 distinct note formats (complete note, missing total, missing measurements, scrambled number order, and a very messy shorthand note). &lt;strong&gt;4 of 5 were fully correct;&lt;/strong&gt; the model left the delivery date empty when I wrote only "Friday" without a specific calendar date, which correctly triggered the fallback rather than guessing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Orders board&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Show "due this week" and "balance pending" cards, filter chips, order cards sorted by delivery date with colored date chips, a bottom sheet to change status or record a payment, and an empty state.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Check:&lt;/em&gt; Orders sort accurately by urgency, and marking an order as "Delivered" instantly drops it from the pending balance total.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Customers and WhatsApp drafts&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Group orders by customer, save a phone number and the latest measurements, and build messages from fixed templates filled in by code. Let Gemma only reword the tone, then verify in code that every number and date is unchanged. If anything changed, or Ollama is off, use the plain template.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Check:&lt;/em&gt; The recipient name, delivery date, and balance matched the order data precisely every single time. When I intentionally tweaked a number in a test prompt, the verification safeguard caught the discrepancy and cleanly defaulted to the plain template.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Design search with SerpApi&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Add an Express server that calls SerpApi, keeping the key in &lt;code&gt;.env&lt;/code&gt;, with caching and a per-session search limit. Let Gemma write two search phrases, and in code remove any phrase containing digits or customer names. Show up to 8 results and let the owner link up to 3 as references, storing only links and titles.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Check:&lt;/em&gt; Repeat searches loaded instantly from the cache, the API key never leaked to the frontend bundle, and turning off the backend server displayed a clean, friendly fallback message.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Screenshots and README&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Write a script that loads fictional sample data and captures phone-sized screenshots into &lt;code&gt;docs/images&lt;/code&gt;, then write a README that describes only features that exist.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  My First User
&lt;/h2&gt;

&lt;p&gt;I showed Stitch Desk to a tailor near me. They have not used it on real orders yet, so this is a first reaction and not a full test.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;First reaction:&lt;/strong&gt; "This looks useful. If I can manage customer measurements and stitching orders in one place, it could save me time."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What they liked:&lt;/strong&gt; Storing customer measurements, tracking order status, and keeping track of delivery dates without relying on notebooks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What they would change:&lt;/strong&gt; No suggestions yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Would they pay?&lt;/strong&gt; I have not asked about a price yet, so I will not guess one.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Honest Limits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ollama has to be running on a computer for the AI features to work. Using it from a phone on the same network may need extra Ollama settings.&lt;/li&gt;
&lt;li&gt;A small local model can still make mistakes with numbers, which is why every draft is reviewed and amounts are verified in code.&lt;/li&gt;
&lt;li&gt;Orders live in one browser's local storage. There is no backup or sync yet, so clearing browser data would erase them.&lt;/li&gt;
&lt;li&gt;Image search depends on a SerpApi plan, and the pictures belong to their original websites. The app links to them and does not copy them.&lt;/li&gt;
&lt;li&gt;I tested with a small number of notes and one tailor's first reaction. I have not tested real daily use or a price.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Best Use of Gemma
&lt;/h3&gt;

&lt;p&gt;Stitch Desk runs &lt;code&gt;gemma3:4b&lt;/code&gt; locally through Ollama for three jobs: turning notes into order cards, rewording message templates, and writing search phrases. In each case the code checks the output (balances computed in code, numbers and dates verified, queries filtered for names and digits), so the model helps without being trusted blindly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Best Use of SerpApi
&lt;/h3&gt;

&lt;p&gt;Design search uses SerpApi's Google Images API through a small server, with the key kept out of the browser. Gemma writes the search phrases, results are cached, and each result links to its source page. The tailor's customers often bring picture references, and this puts them next to the order.&lt;/p&gt;

&lt;h3&gt;
  
  
  Best Use of GitHub Copilot
&lt;/h3&gt;

&lt;p&gt;I built the app by giving GitHub Copilot one prompt at a time and committing after each step: the layout and tabs, the order-card flow, the orders board, the customer screen, the message safeguards, the search server, and the README. Copilot was a development aid only, and it is not needed to run the app.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Excel or file backup and a way to move data between browsers&lt;/li&gt;
&lt;li&gt;Test more note styles, including notes in other languages&lt;/li&gt;
&lt;li&gt;Try other open models and compare them with Gemma on real notes&lt;/li&gt;
&lt;li&gt;Let the tailor try real orders for a week, then ask about price&lt;/li&gt;
&lt;li&gt;A hosted demo for people who do not want to install Ollama&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>Petal &amp; Leaf is a small web app that helps you look at your plants instead of your phone.</title>
      <dc:creator>Vrushali</dc:creator>
      <pubDate>Wed, 07 Oct 2026 11:10:22 +0000</pubDate>
      <link>https://dev.to/vrushali_dev_15/petal-leaf-is-a-small-web-app-that-helps-you-look-at-your-plants-instead-of-your-phone-53fo</link>
      <guid>https://dev.to/vrushali_dev_15/petal-leaf-is-a-small-web-app-that-helps-you-look-at-your-plants-instead-of-your-phone-53fo</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05"&gt;Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Petal &amp;amp; Leaf&lt;/strong&gt; is a small web app that helps you look at your plants instead of your phone.&lt;/p&gt;

&lt;p&gt;I grow a few plants at home, including a tulsi (holy basil) on my balcony. I wanted an app for people like me with a few pots, not one that assumes a big garden. It works for anyone with a balcony, a rooftop, a few pots, or a friend's garden. It has three tabs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Check Plant:&lt;/strong&gt; Take a photo of a leaf, flower, or whole plant. A local AI model gives its best guess at the plant name, a one-line description, any visible problems, a care tip, and a confidence level. It's always labelled &lt;em&gt;"AI guess, not a diagnosis."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quests:&lt;/strong&gt; Three small daily quests for your home plants (I tested with my tulsi), like touching the leaves gently, checking the stems for pests, or listening to the leaves rustle. You tap how the soil feels (Dry, Damp, or Wet) and get advice for that state, plus a seasonal tip.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log:&lt;/strong&gt; Everything you save is kept here with its date, photo, soil state, a short note, and an optional bird-sound recording. A "screen time vs outside time" tracker shows how much of the session you actually spent outside.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The idea is simple: the phone gives you a small job, then you put it away and go touch the soil. The app isn't limited to tulsi, and the photo check works on any plant, leaf, or flower.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Screenshots and photos:&lt;/strong&gt; 
(&lt;a href="https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/h5whpmjbzckv331ddduo.png" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.us-east-2.amazonaws.com/uploads/articles/h5whpmjbzckv331ddduo.png&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Check Plant tab: a photo of tulsi identified as "basil (likely holy basil)" with medium confidence.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Quests tab: AI-generated quests, the soil picker, and Gemma's rephrased seasonal tip.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Log tab: a saved photo analysis, a 9-second bird recording, and quests completed.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/vrush1588" rel="noopener noreferrer"&gt;
        vrush1588
      &lt;/a&gt; / &lt;a href="https://github.com/vrush1588/petal_leaf" rel="noopener noreferrer"&gt;
        petal_leaf
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Screen-free nature quests powered by open-weight Gemma that runs in your browser, offline. 🌱
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/vrush1588/petal_leaf/./images/petal_leaf_banner.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fvrush1588%2Fpetal_leaf%2FHEAD%2F.%2Fimages%2Fpetal_leaf_banner.png" alt="Petal &amp;amp; Leaf balcony garden banner"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🌱 Petal &amp;amp; Leaf&lt;/h1&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;Touch the soil. Look at the leaf. Spot the flower. Phone back in your pocket.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Petal &amp;amp; Leaf gives you small daily quests for your plants (touch the soil
check the leaves, listen for a bird), then helps you log what you found
When available, the open Gemma 3 4B model runs locally through Ollama to
suggest quests, care tips, and photo observations. Built-in advice keeps working
when Ollama is unavailable.&lt;/p&gt;
&lt;p&gt;Built for the DEV Hacktoberfest Open-Source AI Challenge: Week 1 (Touch Grass).&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;App screenshots&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check Plant&lt;/th&gt;
&lt;th&gt;Quests&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer" href="https://github.com/vrush1588/petal_leaf/./images/Screenshot%202026-10-07%20153632.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fvrush1588%2Fpetal_leaf%2FHEAD%2F.%2Fimages%2FScreenshot%25202026-10-07%2520153632.png" alt="Check Plant photo analysis and result"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a rel="noopener noreferrer" href="https://github.com/vrush1588/petal_leaf/./images/Screenshot%202026-10-07%20153949.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fvrush1588%2Fpetal_leaf%2FHEAD%2F.%2Fimages%2FScreenshot%25202026-10-07%2520153949.png" alt="Tulsi quests, soil picker, and seasonal tips"&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Nature log&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/vrush1588/petal_leaf/./images/Screenshot%202026-10-07%20153711.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fvrush1588%2Fpetal_leaf%2FHEAD%2F.%2Fimages%2FScreenshot%25202026-10-07%2520153711.png" alt="Nature log with saved observations and screen/outside tracker"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Gemma use cases&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Petal &amp;amp; Leaf connects to the local &lt;code&gt;gemma3:4b&lt;/code&gt; Ollama model for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Plant photo checks:&lt;/strong&gt; suggest a likely plant, describe visible details
mention visible issues, and offer a photo-specific care tip. This is an AI
guess, not a diagnosis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Daily quest planning:&lt;/strong&gt; create three short, hands-on Tulsi quests using the
selected soil state, season…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/vrush1588/petal_leaf" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The repo has a README and an MIT license.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Stack:&lt;/strong&gt; React + Vite, Ollama running &lt;strong&gt;Gemma (&lt;code&gt;gemma3:4b&lt;/code&gt;)&lt;/strong&gt; on my own laptop, and browser localStorage for the log. I built it one feature at a time with GitHub Copilot prompts, committing after each step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where Gemma is used:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Photo analysis.&lt;/strong&gt; The app resizes the photo and sends it to Gemma through Ollama's &lt;code&gt;/api/chat&lt;/code&gt; endpoint. It asks for a JSON reply with the plant, a short description, issues, a tip, and a confidence level. The prompt tells it never to claim certainty.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Daily quests and soil advice.&lt;/strong&gt; Gemma writes three quests from the plant, the soil state, the season, and where I am (my balcony or a friend's garden).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Friendly seasonal tips.&lt;/strong&gt; I keep a small table of tulsi tips for each season and let Gemma rephrase it in a friendly voice. The facts come from my table, and Gemma only handles the wording.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Safety net:&lt;/strong&gt; If the model is off or returns bad JSON, the app falls back to simple built-in rules, so it never breaks.&lt;/p&gt;

&lt;h3&gt;
  
  
  What went wrong (and what I changed)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Running Gemma in the browser failed.&lt;/strong&gt; My first plan was fully in-browser Gemma through MediaPipe, so a phone could run it with no laptop. The model wouldn't load and the app showed a fallback message. I switched to local Ollama. The app now needs my laptop, so it isn't truly offline on a phone yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The first advice was vague.&lt;/strong&gt; With the soil set to &lt;em&gt;Wet&lt;/em&gt;, the AI said something like "maintain consistent soil moisture," which isn't helpful. I made the soil state a strict rule in the prompt and added a code check so wet soil never gets a "water it" suggestion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The quests repeated themselves.&lt;/strong&gt; Two of the three were about pests. I changed the prompt to require different kinds of quests: one about the soil, one about the leaves, and one about smelling or listening.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I almost built the wrong thing.&lt;/strong&gt; My first idea was a bird-call identifier. Then I realised birds stop singing the second you press record, so I made the plant check the main feature. Bird sounds became an optional quest where you record a clip and note what you heard.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;My photos and notes stay on my machine.&lt;/strong&gt; Pictures of my plants and my log go to Gemma on my own laptop, not to someone else's server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It costs nothing to run.&lt;/strong&gt; No API key and no per-photo charge, so I could take as many test photos as I wanted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I could change how it behaves.&lt;/strong&gt; Because I control the model and the prompts, I tightened the soil rule and fixed the repeated quests as soon as I saw the problems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I could see the limits.&lt;/strong&gt; Running the model myself made it clear what a 4B model can and can't do, which brings me to the honest part below.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Honest Notes: What Worked and What Didn't
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Gemma named my &lt;strong&gt;tulsi photo&lt;/strong&gt; as "basil (likely holy basil)" with &lt;em&gt;medium&lt;/em&gt; confidence. It got the plant family right and was cautious about the exact type.&lt;/li&gt;
&lt;li&gt;On a &lt;strong&gt;bouquet of roses&lt;/strong&gt;, it said "roses" and "none noticed" for issues. Its care tip about drainage was generic and not tied to anything visible in the photo.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"No visible issues" from a small model shouldn't be trusted blindly. That's why every result carries the "not a diagnosis" label.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Touch Grass field test:&lt;/strong&gt; I tested on my balcony. Screen time: &lt;em&gt;5 min&lt;/em&gt;. Outside time: &lt;em&gt;20 min&lt;/em&gt;. I did: touched the soil, checked the leaves. Did you hear a bird, or only rustling leaves?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Limits:&lt;/strong&gt; It needs Ollama running on a laptop, I tested it mostly on tulsi, and the soil state is tapped by hand because moisture can't be judged reliably from a photo.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;Example prompts used with GitHub Copilot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;“Create a mobile-first React + Vite plant-care app with a soft pastel green theme, daily Tulsi quests, and a local observation log.”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;“Use my local Ollama gemma3:4b model to generate safe daily quests and analyze plant photos. Resize images before sending, parse JSON safely, and keep built-in advice as a fallback.”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;“Add a four-season Tulsi tips table, optional bird-listening notes and recordings, and a screen-time vs. outside-time tracker.”
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Best Use of Gemma
&lt;/h3&gt;

&lt;p&gt;Petal &amp;amp; Leaf connects to the local &lt;code&gt;gemma3:4b&lt;/code&gt; model through Ollama. Gemma does three jobs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Plant photo checks:&lt;/strong&gt; It suggests a likely plant, describes visible details, mentions visible issues, and gives a care tip based on the photo. This is an AI guess, not a diagnosis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Daily quest planning:&lt;/strong&gt; It creates three short, hands-on quests for my tulsi, using the soil state, the season, and where I am.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Friendly seasonal care:&lt;/strong&gt; It rephrases the current seasonal tip from my table in a welcoming voice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Photo checks are optional, and the app resizes photos before sending them to Ollama. The app does not identify birds. The bird quest only records a clip and a note.&lt;/p&gt;

&lt;h3&gt;
  
  
  Best Use of GitHub Copilot
&lt;/h3&gt;

&lt;p&gt;I built Petal &amp;amp; Leaf by giving GitHub Copilot one prompt at a time and committing after each step. Copilot helped me with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building the React components and mobile-first styles&lt;/li&gt;
&lt;li&gt;Writing the Ollama API integration and the JSON response handling&lt;/li&gt;
&lt;li&gt;Adding the tabs layout, local-first logging, and fallback behavior&lt;/li&gt;
&lt;li&gt;Fixing the soil-advice rules and the repeated quests&lt;/li&gt;
&lt;li&gt;Writing the README and setup steps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Copilot was a development aid only. It is not needed to run the app, because the runtime AI features use the local Ollama model.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Run Gemma inside the browser so it works on a phone with no laptop&lt;/li&gt;
&lt;li&gt;A native Android version using on-device Gemma&lt;/li&gt;
&lt;li&gt;Bird identification with BirdNET&lt;/li&gt;
&lt;li&gt;A "walk quest" that sends you to the nearest park&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>touchthegrass</category>
    </item>
    <item>
      <title>What is SerpApi, and why I built LearnBeacon on it</title>
      <dc:creator>Vrushali</dc:creator>
      <pubDate>Tue, 06 Oct 2026 13:50:00 +0000</pubDate>
      <link>https://dev.to/vrushali_dev_15/what-is-serpapi-and-why-i-built-learnbeacon-on-it-59ia</link>
      <guid>https://dev.to/vrushali_dev_15/what-is-serpapi-and-why-i-built-learnbeacon-on-it-59ia</guid>
      <description>&lt;p&gt;🚀 &lt;strong&gt;How I Built LearnBeacon with SerpApi&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Students often search across multiple websites for colleges, scholarships, careers and study resources.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;LearnBeacon&lt;/strong&gt; to bring this research into one place using &lt;strong&gt;SerpApi + an AI research agent&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;🔎 What I learned:&lt;br&gt;
• Live search data instead of outdated datasets&lt;br&gt;
• One API for Web, Maps, News, YouTube, Jobs &amp;amp; more&lt;br&gt;
• 30-minute caching to reduce API usage&lt;br&gt;
• Source links for better trust&lt;br&gt;
• Fallback data when the API is unavailable&lt;br&gt;
• Not every query needs AI — a simple router decides when to use the agent&lt;/p&gt;

&lt;p&gt;🎥 &lt;strong&gt;2-minute demo:&lt;/strong&gt; &lt;a href="https://youtu.be/Mkzj8lA4yRc" rel="noopener noreferrer"&gt;https://youtu.be/Mkzj8lA4yRc&lt;/a&gt;&lt;br&gt;
💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/vrush1588/LearnBeacon" rel="noopener noreferrer"&gt;https://github.com/vrush1588/LearnBeacon&lt;/a&gt;&lt;br&gt;
📝 &lt;strong&gt;What is SerpApi &amp;amp; why I built LearnBeacon:&lt;/strong&gt; &lt;a href="https://medium.com/@vrushalidev/what-is-serpapi-and-why-i-built-learnbeacon-on-it-e1b93bf9ecd4" rel="noopener noreferrer"&gt;https://medium.com/@vrushalidev/what-is-serpapi-and-why-i-built-learnbeacon-on-it-e1b93bf9ecd4&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're building an AI app that needs &lt;strong&gt;real-time web research&lt;/strong&gt;, SerpApi is worth exploring.&lt;/p&gt;

&lt;h1&gt;
  
  
  SerpApi #AI #AIagents #BuildInPublic #WebDevelopment #Education #Hackathon
&lt;/h1&gt;

</description>
      <category>ai</category>
      <category>gemini</category>
      <category>softwaredevelopment</category>
      <category>hackathon</category>
    </item>
    <item>
      <title>I Built a Voice-First AI Learning Companion That Doesn't Just Give Students Answers</title>
      <dc:creator>Vrushali</dc:creator>
      <pubDate>Sat, 26 Sep 2026 09:36:20 +0000</pubDate>
      <link>https://dev.to/vrushali_dev_15/i-built-a-voice-first-ai-learning-companion-that-doesnt-just-give-students-answers-2nea</link>
      <guid>https://dev.to/vrushali_dev_15/i-built-a-voice-first-ai-learning-companion-that-doesnt-just-give-students-answers-2nea</guid>
      <description>&lt;p&gt;&lt;strong&gt;What if an AI tutor didn't immediately give students the answer?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What if, instead, it encouraged them to &lt;strong&gt;think first, explain their reasoning, and discover the answer through conversation&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;That question led me to build &lt;strong&gt;ThinkShiftAI&lt;/strong&gt; — a voice-first AI learning companion for students, built for the Agora Voice AI Hackathon.&lt;/p&gt;

&lt;p&gt;The core idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ask → Think → Talk → Discover&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;❌ Ask → Answer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  🎯 Why I Built It
&lt;/h2&gt;

&lt;p&gt;When a student gets stuck, the easiest thing for an AI to do is hand over the solution. But getting the answer isn't the same as understanding the concept.&lt;/p&gt;

&lt;p&gt;Say a student points at a math problem and asks &lt;em&gt;"can you help me solve this?"&lt;/em&gt; Instead of dumping the full solution, ThinkShiftAI nudges with questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What do you already know?&lt;/li&gt;
&lt;li&gt;Which part is confusing?&lt;/li&gt;
&lt;li&gt;What would you try first?&lt;/li&gt;
&lt;li&gt;Why do you think that approach works?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal isn't to make the student struggle — it's to create a small, useful pause between &lt;em&gt;asking&lt;/em&gt; and &lt;em&gt;receiving&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎙️ Why Voice
&lt;/h2&gt;

&lt;p&gt;Learning doesn't have to happen through typing. A student can just say &lt;em&gt;"I don't understand this step"&lt;/em&gt; and keep going — no retyping, no re-reading a wall of text. It feels closer to talking with a tutor than querying a chatbot.&lt;/p&gt;

&lt;p&gt;The voice layer runs on &lt;strong&gt;Agora Conversational AI&lt;/strong&gt;; the app itself is &lt;strong&gt;Flutter&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧩 How It Works
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Student
   ↓ speaks a question
Voice AI (Agora RTC)
   ↓
AI understands the question
   ↓
ThinkShift reasoning
   ↓
Guiding question / explanation
   ↓
Student responds → conversation continues
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not &lt;code&gt;Question → Answer&lt;/code&gt;. Instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Question → Understand → Guide → Student thinks → Student responds → Discover
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🛠️ Tech Stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Tech&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mobile&lt;/td&gt;
&lt;td&gt;Flutter (Dart), Android&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Voice&lt;/td&gt;
&lt;td&gt;Agora RTC + Agora Conversational AI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;STT&lt;/td&gt;
&lt;td&gt;Deepgram &lt;code&gt;nova-3&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LLM&lt;/td&gt;
&lt;td&gt;OpenAI &lt;code&gt;gpt-4o-mini&lt;/code&gt;, prompted for the "one guiding question, never a quiz" rule&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TTS&lt;/td&gt;
&lt;td&gt;MiniMax &lt;code&gt;speech-2.8-turbo&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;Python, Flask&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Kept the architecture simple on purpose — simple enough to demo cleanly, but real enough to show how a modern voice-AI pipeline actually connects together.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧠 The Interesting Problem: Don't Let the Tutor Become Annoying
&lt;/h2&gt;

&lt;p&gt;If the AI keeps firing back &lt;em&gt;"what do you think?"&lt;/em&gt; to every single message, the conversation turns frustrating fast. So the tutor has to balance:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Guidance ↔ Explanation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sometimes the student needs a hint. Sometimes an example. Sometimes they just need the answer explained plainly. Getting that balance right — mostly through prompt design and keeping responses to 1–3 sentences with &lt;em&gt;at most one&lt;/em&gt; guiding question — turned out to be one of the more interesting product problems, not a modeling problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  👩‍🎓 A Sample Interaction
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Student:&lt;/strong&gt; "I don't know how to start this problem."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ThinkShift:&lt;/strong&gt; "What information do you already have?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Student:&lt;/strong&gt; "We know the distance and time."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ThinkShift:&lt;/strong&gt; "Great — if you know distance and time, which formula connects those two?"&lt;/p&gt;

&lt;p&gt;The student is still doing the thinking. The AI acts like a learning companion, not an answer machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  📷 Camera + Voice
&lt;/h2&gt;

&lt;p&gt;The newest piece I've shipped: a student can &lt;strong&gt;point their phone at a handwritten problem, and ThinkShift talks about it&lt;/strong&gt; — no typing, no switching screens.&lt;/p&gt;

&lt;p&gt;Here's how it works under the hood:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Student snaps a photo of the problem.&lt;/li&gt;
&lt;li&gt;A vision model (I went with Gemini's free tier here, since it handles image understanding well without needing a paid key) produces a short description of what's on the page — without solving it.&lt;/li&gt;
&lt;li&gt;That description gets injected into the &lt;em&gt;already-running&lt;/em&gt; voice session via Agora's &lt;code&gt;think&lt;/code&gt; endpoint, so the same agent that's been talking to the student responds naturally, in the same voice, in the same conversation — no separate UI, no context switch.&lt;/li&gt;
&lt;li&gt;The agent reacts the way it would to anything else the student says: one guiding question, not the answer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The nice part is the architecture: instead of bolting on a separate "photo analysis" screen, the photo just becomes another turn in the same conversation. The student never leaves the voice experience — they show ThinkShift something, and it responds out loud, like they would to a person sitting next to them.&lt;/p&gt;

&lt;p&gt;Next up on the roadmap: multilingual support (Hindi, Marathi), subject-specific tutoring modes, adaptive difficulty, and a simple student progress view.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 What I Learned
&lt;/h2&gt;

&lt;p&gt;Building this pushed me to think past "connect an LLM to a chat screen." A good AI product also has to reason about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How the conversation should &lt;em&gt;flow&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;When to explain vs. when to ask&lt;/li&gt;
&lt;li&gt;How much guidance is the right amount&lt;/li&gt;
&lt;li&gt;How voice changes the interaction entirely&lt;/li&gt;
&lt;li&gt;How to keep it feeling natural, not scripted&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The model is one part of the product. &lt;strong&gt;Interaction design is the other, bigger part.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🔗 Try It
&lt;/h2&gt;

&lt;p&gt;🎥 &lt;strong&gt;Demo:&lt;/strong&gt; &lt;a href="https://www.youtube.com/watch?v=e1_AwnC8GOs&amp;amp;t=37s" rel="noopener noreferrer"&gt;Watch on YouTube&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/vrush1588/ThinkShiftAI-Voice-First-Conversational-Learning" rel="noopener noreferrer"&gt;ThinkShiftAI-Voice-First-Conversational-Learning&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Built for the &lt;strong&gt;Agora Voice AI Hackathon&lt;/strong&gt;, powered by &lt;strong&gt;Agora Conversational AI&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I'd love to hear how you'd design a voice-first AI tutor — would you make it answer immediately, or make it guide the student first?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;#AI #VoiceAI #Flutter #EdTech #ConversationalAI #Agora #GenerativeAI #Learning&lt;/code&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>buildinpublic</category>
      <category>learning</category>
      <category>agora</category>
    </item>
    <item>
      <title>Java Streams 101: The Beginner Cheat Sheet for Interviews ☕️</title>
      <dc:creator>Vrushali</dc:creator>
      <pubDate>Tue, 22 Sep 2026 14:10:50 +0000</pubDate>
      <link>https://dev.to/vrushali_dev_15/java-streams-101-the-beginner-cheat-sheet-for-interviews-3nln</link>
      <guid>https://dev.to/vrushali_dev_15/java-streams-101-the-beginner-cheat-sheet-for-interviews-3nln</guid>
      <description>&lt;p&gt;&lt;strong&gt;Java Streams confused you at first? 😵&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You're not alone.&lt;/p&gt;

&lt;p&gt;When you first see code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
       &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(...)&lt;/span&gt;
       &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(...)&lt;/span&gt;
       &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sorted&lt;/span&gt;&lt;span class="o"&gt;(...)&lt;/span&gt;
       &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(...);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it can feel like a lot of methods to remember.&lt;/p&gt;

&lt;p&gt;But there is a simpler way to understand Streams:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Think of a Stream as a pipeline for processing data.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The data enters the pipeline, gets processed step by step, and produces a result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Data
  ↓
stream()
  ↓
filter()
  ↓
map()
  ↓
sorted()
  ↓
collect()
  ↓
Result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break down the most useful operations.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. &lt;code&gt;filter()&lt;/code&gt; → Keep what you need 🔍
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;filter()&lt;/code&gt; keeps elements that match a condition.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;evenNumbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[2, 4]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Think:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;filter = “Should this value stay?”&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  2. &lt;code&gt;map()&lt;/code&gt; → Transform the values 🔄
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;map()&lt;/code&gt; changes each element into something else.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;doubled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[2, 4, 6, 8, 10]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Think:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;map = “Change this value.”&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  3. &lt;code&gt;flatMap()&lt;/code&gt; → Flatten nested data 📦
&lt;/h2&gt;

&lt;p&gt;This one often confuses beginners.&lt;/p&gt;

&lt;p&gt;Suppose you have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using &lt;code&gt;flatMap()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;List:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 2, 3, 4]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without flattening:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[[1, 2], [3, 4]]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After flattening:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 2, 3, 4]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Think:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;flatMap = “Take nested data and flatten it into one Stream.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A simple mental picture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[[1,2], [3,4]]
       ↓
   flatMap()
       ↓
 [1,2,3,4]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. &lt;code&gt;sorted()&lt;/code&gt; → Sort the data 🔢
&lt;/h2&gt;

&lt;p&gt;Need the elements in order?&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;sorted()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sorted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sorted&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 2, 3, 4, 5]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For descending order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;descending&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sorted&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Comparator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reverseOrder&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Think:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;sorted = “Put the values in order.”&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  5. &lt;code&gt;collect()&lt;/code&gt; → Gather the result 🧺
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;collect()&lt;/code&gt; is commonly used to gather Stream elements into a collection or another result structure.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[3, 4, 5]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In modern Java, you may also see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Think:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;collect = “Gather the processed values.”&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  6. &lt;code&gt;reduce()&lt;/code&gt; → Combine into ONE result ➕
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;reduce()&lt;/code&gt; is different.&lt;/p&gt;

&lt;p&gt;Instead of returning multiple processed elements, it combines them into a single result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reduce&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;Integer:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;15
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visualize it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 → 2 → 3 → 4 → 5
        ↓
      reduce()
        ↓
       15
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Think:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;reduce = “Combine many values into one.”&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Cheat Sheet 📝
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Simple meaning&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;filter()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Keep what matches&lt;/td&gt;
&lt;td&gt;&lt;code&gt;n -&amp;gt; n &amp;gt; 2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;map()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Transform values&lt;/td&gt;
&lt;td&gt;&lt;code&gt;n -&amp;gt; n * 2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;flatMap()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Flatten nested data&lt;/td&gt;
&lt;td&gt;Lists → one Stream&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sorted()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sort elements&lt;/td&gt;
&lt;td&gt;ascending/descending&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;collect()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Gather the result&lt;/td&gt;
&lt;td&gt;Stream → List&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;reduce()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Combine into one&lt;/td&gt;
&lt;td&gt;sum, product, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  One Pipeline to Remember 🚀
&lt;/h2&gt;

&lt;p&gt;Imagine you have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You want:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;even numbers → double them → sort them → collect them&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sorted&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step by step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Original
[5, 2, 8, 1, 4]

      ↓ filter()

[2, 8, 4]

      ↓ map()

[4, 16, 8]

      ↓ sorted()

[4, 8, 16]

      ↓ toList()

[4, 8, 16]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the power of the Stream pipeline.&lt;/p&gt;




&lt;h2&gt;
  
  
  One More Interview Concept: Lambda vs Predicate 🤔
&lt;/h2&gt;

&lt;p&gt;You might see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, you're passing a &lt;strong&gt;lambda expression&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;filter()&lt;/code&gt; expects a &lt;code&gt;Predicate&lt;/code&gt;, which is a functional interface representing a condition that returns &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Lambda
   ↓
n -&amp;gt; n &amp;gt; 10
   ↓
used as a Predicate
   ↓
filter()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't need to explicitly create a &lt;code&gt;Predicate&lt;/code&gt; every time.&lt;/p&gt;

&lt;p&gt;This is perfectly normal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Mental Model 🧠
&lt;/h2&gt;

&lt;p&gt;Don't memorize Streams as a collection of random methods.&lt;/p&gt;

&lt;p&gt;Remember the pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FILTER
  ↓
Keep

MAP
  ↓
Transform

FLATMAP
  ↓
Flatten

SORTED
  ↓
Order

COLLECT
  ↓
Gather

REDUCE
  ↓
Combine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or even simpler:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Filter → Transform → Organize → Collect OR Reduce&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once this mental model clicks, Java Streams become much less intimidating.&lt;/p&gt;

&lt;p&gt;And when an interviewer asks:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“Can you explain Java Streams?”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;you don't have to start by listing 20 methods.&lt;/p&gt;

&lt;p&gt;Start with the idea:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A Stream provides a pipeline for processing elements from a data source using operations such as filtering, transforming, sorting, collecting, and reducing.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then show a small example.&lt;/p&gt;

&lt;p&gt;That's usually much easier to explain than trying to memorize definitions. ☕️&lt;/p&gt;




&lt;h3&gt;
  
  
  What Stream operation confused you the most when you first learned Java?
&lt;/h3&gt;

&lt;h1&gt;
  
  
  Java #JavaStreams #JavaInterview #JavaProgramming #LearnJava #Coding #Programming #Developer
&lt;/h1&gt;

</description>
      <category>beginners</category>
      <category>interview</category>
      <category>java</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Upgrade Your Skills with IBM SkillsBuild 🚀</title>
      <dc:creator>Vrushali</dc:creator>
      <pubDate>Fri, 18 Sep 2026 14:35:20 +0000</pubDate>
      <link>https://dev.to/vrushali_dev_15/upgrade-your-skills-with-ibm-skillsbuild-341c</link>
      <guid>https://dev.to/vrushali_dev_15/upgrade-your-skills-with-ibm-skillsbuild-341c</guid>
      <description>&lt;h2&gt;
  
  
  Upgrade Your Skills with IBM SkillsBuild 🚀
&lt;/h2&gt;

&lt;p&gt;If you're a developer or someone trying to grow your tech skills, finding good learning resources can sometimes be overwhelming.&lt;/p&gt;

&lt;p&gt;I recently came across &lt;strong&gt;IBM SkillsBuild&lt;/strong&gt;, a platform with free learning resources covering areas like:&lt;/p&gt;

&lt;p&gt;💻 Programming&lt;br&gt;
🤖 Artificial Intelligence&lt;br&gt;
☁️ Cloud&lt;br&gt;
🔐 Cybersecurity&lt;br&gt;
📊 Data &amp;amp; Analytics&lt;br&gt;
🧠 Emerging technologies&lt;/p&gt;

&lt;p&gt;What I like is that you can explore topics based on your current level and learn at your own pace.&lt;/p&gt;

&lt;p&gt;Whether you're a beginner starting your programming journey or a developer looking to explore a new area, it's worth checking out.&lt;/p&gt;

&lt;p&gt;I'm always trying to learn something new and keep my skills updated, especially as technology and AI continue to change so quickly.&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;Explore IBM SkillsBuild:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://skillsbuild.org/learning-catalog?q=programming" rel="noopener noreferrer"&gt;https://skillsbuild.org/learning-catalog?q=programming&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What are you currently learning or planning to learn next? 👇&lt;/p&gt;

&lt;h1&gt;
  
  
  IBM #SkillsBuild #Programming #AI #Learning #Developers #TechCommunity #100DaysOfCode
&lt;/h1&gt;

</description>
      <category>learning</category>
      <category>ai</category>
      <category>100daysofcode</category>
      <category>ibm</category>
    </item>
    <item>
      <title>Did you know you can swap two variables in Dart without using a temporary variable?</title>
      <dc:creator>Vrushali</dc:creator>
      <pubDate>Fri, 18 Sep 2026 07:41:43 +0000</pubDate>
      <link>https://dev.to/vrushali_dev_15/did-you-know-you-can-swap-two-variables-in-dart-without-using-a-temporary-variable-4p4i</link>
      <guid>https://dev.to/vrushali_dev_15/did-you-know-you-can-swap-two-variables-in-dart-without-using-a-temporary-variable-4p4i</guid>
      <description>&lt;p&gt;🔄 &lt;strong&gt;Did you know you can swap two variables in Dart without using a temporary variable?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In many programming languages, we usually need a third variable to swap two values.&lt;/p&gt;

&lt;p&gt;But Dart makes this really simple using &lt;strong&gt;multiple assignment&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 20&lt;/span&gt;
&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✨ &lt;strong&gt;What’s happening here?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;(b, a)&lt;/code&gt; creates the new values, and Dart assigns them back to &lt;code&gt;(a, b)&lt;/code&gt; in the same statement.&lt;/p&gt;

&lt;p&gt;So:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;a = 10, b = 20&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;becomes:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;a = 20, b = 10&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;No extra temporary variable needed. 🚀&lt;/p&gt;

&lt;p&gt;A small Dart feature, but a nice trick to know when writing clean and concise code.&lt;/p&gt;

&lt;h1&gt;
  
  
  Dart #Flutter #Programming #CodingTips #LearnDart #SoftwareDevelopment
&lt;/h1&gt;

</description>
      <category>dart</category>
      <category>flutter</category>
      <category>coding</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>What if AI could understand India better?</title>
      <dc:creator>Vrushali</dc:creator>
      <pubDate>Wed, 16 Sep 2026 10:25:05 +0000</pubDate>
      <link>https://dev.to/vrushali_dev_15/what-if-ai-could-understand-india-better-paj</link>
      <guid>https://dev.to/vrushali_dev_15/what-if-ai-could-understand-india-better-paj</guid>
      <description>&lt;p&gt;🇮🇳 &lt;strong&gt;What if AI could understand India better?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Meet &lt;strong&gt;Sarvam AI&lt;/strong&gt; — an Indian AI company building AI technologies with a strong focus on Indian languages, speech, and real-world use cases.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.sarvam.ai/" rel="noopener noreferrer"&gt;SarvamAI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From &lt;strong&gt;Marathi and Hindi to 20+ Indian languages&lt;/strong&gt;, Sarvam is working on making AI more accessible across India's diverse linguistic landscape. 🤖🇮🇳&lt;/p&gt;

&lt;p&gt;As a developer, I find this especially interesting because the future of AI isn't just about bigger models — it's also about:&lt;/p&gt;

&lt;p&gt;🗣️ Understanding local languages &amp;amp; voices&lt;br&gt;
🌐 Building for multilingual users&lt;br&gt;
📱 Bringing AI into real-world applications&lt;br&gt;
🇮🇳 Creating technology for India's unique needs&lt;/p&gt;

&lt;p&gt;I'm excited to explore how &lt;strong&gt;Indian-language AI APIs and models&lt;/strong&gt; can be used in Android and mobile applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI that doesn't just work for India — but understands India. 🇮🇳&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;#SarvamAI #IndianAI #IndiaAI #AI #GenAI #Kotlin #Android #MobileDevelopment&lt;/p&gt;

</description>
      <category>ai</category>
      <category>sarvamai</category>
      <category>productivity</category>
      <category>mobiledev</category>
    </item>
    <item>
      <title>Siri Is Moving From Voice Assistant to AI Agent 🍎🤖</title>
      <dc:creator>Vrushali</dc:creator>
      <pubDate>Wed, 09 Sep 2026 19:28:28 +0000</pubDate>
      <link>https://dev.to/vrushali_dev_15/siri-is-moving-from-voice-assistant-to-ai-agent-f16</link>
      <guid>https://dev.to/vrushali_dev_15/siri-is-moving-from-voice-assistant-to-ai-agent-f16</guid>
      <description>&lt;p&gt;Apple’s latest Siri direction caught my attention—not because Siri can answer questions, but because of &lt;strong&gt;what happens next&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The interesting shift is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Voice assistant → AI assistant → AI agent&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Traditional voice assistants mostly work like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Set an alarm.”&lt;br&gt;
“Play music.”&lt;br&gt;
“What’s the weather?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But the next generation is about understanding &lt;strong&gt;context&lt;/strong&gt;, interacting with apps, and taking actions on the user’s behalf.&lt;/p&gt;

&lt;p&gt;Think:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;User intent → AI reasoning → app/tool → action → result&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That changes how we should think about mobile apps.&lt;/p&gt;

&lt;p&gt;Apps may no longer be built only for humans tapping through screens. They also need to expose &lt;strong&gt;useful, safe, structured capabilities&lt;/strong&gt; that AI systems can understand and invoke.&lt;/p&gt;

&lt;p&gt;For developers, this raises some interesting questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How should apps expose capabilities to AI agents?&lt;/li&gt;
&lt;li&gt;How do we handle permissions and user consent?&lt;/li&gt;
&lt;li&gt;How do we make agent actions safe and idempotent?&lt;/li&gt;
&lt;li&gt;What information should stay on-device?&lt;/li&gt;
&lt;li&gt;When should AI use the cloud?&lt;/li&gt;
&lt;li&gt;How should apps return structured results to an agent?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where I think mobile development is heading.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The future app may not always start with a screen.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sometimes it may start with:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Hey Siri, do this for me.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And the AI figures out &lt;strong&gt;which app, which capability, and which action&lt;/strong&gt; is needed.&lt;/p&gt;

&lt;p&gt;As Android developers, this is a space worth watching closely too. 🚀&lt;/p&gt;

&lt;h1&gt;
  
  
  AI #AIAgents #Siri #Apple #MobileDevelopment #AndroidDev #iOSDev #GenAI
&lt;/h1&gt;

</description>
      <category>ai</category>
      <category>appleevent</category>
      <category>agents</category>
      <category>ios</category>
    </item>
    <item>
      <title>Don’t Just Solve the Code. Understand the Approach. 🧠💻</title>
      <dc:creator>Vrushali</dc:creator>
      <pubDate>Fri, 14 Aug 2026 14:22:14 +0000</pubDate>
      <link>https://dev.to/vrushali_dev_15/dont-just-solve-the-code-understand-the-approach-5bcb</link>
      <guid>https://dev.to/vrushali_dev_15/dont-just-solve-the-code-understand-the-approach-5bcb</guid>
      <description>&lt;p&gt;Writing code that produces the correct output is only the beginning.&lt;/p&gt;

&lt;p&gt;The real challenge in &lt;strong&gt;DSA and System Design&lt;/strong&gt; is understanding &lt;em&gt;why&lt;/em&gt; your solution works—and whether there is a better way to solve the problem.&lt;/p&gt;

&lt;p&gt;For example, when using a &lt;strong&gt;brute-force approach&lt;/strong&gt;, we try every possible solution.&lt;/p&gt;

&lt;p&gt;It may work. ✅&lt;/p&gt;

&lt;p&gt;But as developers, we should ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why does this approach work?&lt;/li&gt;
&lt;li&gt;What is the &lt;strong&gt;time complexity&lt;/strong&gt;?&lt;/li&gt;
&lt;li&gt;What is the &lt;strong&gt;space complexity&lt;/strong&gt;?&lt;/li&gt;
&lt;li&gt;Can I optimize it?&lt;/li&gt;
&lt;li&gt;Is there a better algorithm?&lt;/li&gt;
&lt;li&gt;What problem-solving pattern am I actually using?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These questions move us from simply &lt;strong&gt;writing code&lt;/strong&gt; to actually &lt;strong&gt;thinking like engineers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/QIiPaCEQ5TY"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bigger Lesson
&lt;/h2&gt;

&lt;p&gt;Learning DSA isn't just about memorizing algorithms or solving hundreds of coding problems.&lt;/p&gt;

&lt;p&gt;It's about developing the ability to recognize patterns, evaluate trade-offs, and choose the right approach.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Writing code is one skill.&lt;br&gt;&lt;br&gt;
Understanding the algorithm behind the code is the skill that scales.&lt;/strong&gt; 🚀&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What do you focus on after solving a DSA problem—optimization, complexity, or understanding the pattern?&lt;/p&gt;

</description>
      <category>programming</category>
      <category>dsa</category>
      <category>leetcode</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>🌳 Why Every Android Developer Should Actually Understand Trees (Not Just Memorize Them)</title>
      <dc:creator>Vrushali</dc:creator>
      <pubDate>Fri, 07 Aug 2026 13:48:29 +0000</pubDate>
      <link>https://dev.to/vrushali_dev_15/why-every-android-developer-should-actually-understand-trees-not-just-memorize-them-2ch7</link>
      <guid>https://dev.to/vrushali_dev_15/why-every-android-developer-should-actually-understand-trees-not-just-memorize-them-2ch7</guid>
      <description>&lt;p&gt;🌳 Why Every Android Developer Should Actually Understand Trees&lt;/p&gt;

&lt;p&gt;If you've been learning Data Structures, you probably started with &lt;strong&gt;Arrays&lt;/strong&gt;, &lt;strong&gt;Linked Lists&lt;/strong&gt;, &lt;strong&gt;Stacks&lt;/strong&gt;, and &lt;strong&gt;Queues&lt;/strong&gt; — they store data in a straight line, so they're easy to picture.&lt;/p&gt;

&lt;p&gt;But here's the thing: &lt;strong&gt;almost nothing in Android is a straight line.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your screen isn't a list of views sitting one after another — it's a &lt;em&gt;hierarchy&lt;/em&gt;. Your navigation isn't a single path — it's a &lt;em&gt;branching structure&lt;/em&gt;. Your JSON response, your Room database indexes, your Jetpack Compose UI — all of them are &lt;strong&gt;Trees&lt;/strong&gt; wearing different costumes.&lt;/p&gt;

&lt;p&gt;So today, let's actually understand what a Tree is, why it matters, and — more importantly — where you're &lt;em&gt;already&lt;/em&gt; using one without realizing it.&lt;/p&gt;




&lt;h2&gt;
  
  
  🌱 What is a Tree?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Tree&lt;/strong&gt; is a data structure where data is organized in a &lt;strong&gt;parent-child relationship&lt;/strong&gt;, starting from a single node called the &lt;strong&gt;Root&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;           Root
          /    \
      Child1  Child2
       /   \
 Grand1  Grand2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of storing items one after another like an array, a tree lets data &lt;strong&gt;branch into multiple paths&lt;/strong&gt;. Every item in a tree is called a &lt;strong&gt;Node&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core terminology
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Term&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Root&lt;/td&gt;
&lt;td&gt;The topmost node with no parent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parent&lt;/td&gt;
&lt;td&gt;A node that has one or more child nodes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Child&lt;/td&gt;
&lt;td&gt;A node connected below a parent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Leaf&lt;/td&gt;
&lt;td&gt;A node with no children&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              A
            /   \
          B       C
         / \
        D   E
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A&lt;/strong&gt; → Root&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;B, C&lt;/strong&gt; → Children of A&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;D, E&lt;/strong&gt; → Leaf Nodes (nothing branches below them)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simple so far — but here's why it actually matters for the app you're shipping.&lt;/p&gt;




&lt;h2&gt;
  
  
  📱 Where Trees Are Hiding in Your Android App
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. The View Hierarchy
&lt;/h3&gt;

&lt;p&gt;Every XML layout you've ever written is a tree. A &lt;code&gt;ConstraintLayout&lt;/code&gt; is the root, it has children like &lt;code&gt;TextView&lt;/code&gt;, &lt;code&gt;RecyclerView&lt;/code&gt;, &lt;code&gt;Button&lt;/code&gt;, and those children can have children of their own (nested layouts). When Android measures and draws your screen, it's literally doing a &lt;strong&gt;tree traversal&lt;/strong&gt; — walking down from the root view to every leaf, then back up.&lt;/p&gt;

&lt;p&gt;That's why deeply nested layouts hurt performance: you've built a taller, heavier tree, and every traversal costs more.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Jetpack Compose's UI Tree
&lt;/h3&gt;

&lt;p&gt;Compose didn't remove the tree — it made it explicit. Every &lt;code&gt;@Composable&lt;/code&gt; function you call becomes a node in Compose's internal tree. Recomposition works by comparing this tree against the previous one and only re-rendering the branches that changed. Understanding "why did my whole screen recompose instead of just one item" becomes a lot clearer once you think of your UI as a tree, not a flat list of functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The Navigation Graph
&lt;/h3&gt;

&lt;p&gt;Your &lt;code&gt;NavGraph&lt;/code&gt; — whether it's XML-based or Compose Navigation — is a tree (technically a directed graph, but structured like nested trees for nested graphs). Screens are nodes, navigation actions are edges, and nested graphs (like an onboarding flow inside your main app) are subtrees.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. RecyclerView Sections &amp;amp; Expandable Lists
&lt;/h3&gt;

&lt;p&gt;Ever built a &lt;code&gt;RecyclerView&lt;/code&gt; with expandable/collapsible sections, or a chat app with threaded replies? That's a tree rendered as a flat list — you're flattening a hierarchy into rows the same way a file explorer flattens folders into a scrollable view.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Room / SQLite Indexes
&lt;/h3&gt;

&lt;p&gt;When you add an &lt;code&gt;@Index&lt;/code&gt; to a Room entity for faster queries, the database engine is very likely building something like a &lt;strong&gt;B-Tree&lt;/strong&gt; under the hood. That's &lt;em&gt;why&lt;/em&gt; indexed lookups are fast — the database doesn't scan every row, it walks down a tree the same way you'd search a Binary Search Tree.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Parsing JSON and Deep Links
&lt;/h3&gt;

&lt;p&gt;A JSON response with nested objects and arrays &lt;em&gt;is&lt;/em&gt; a tree. When you deserialize it with Moshi, Gson, or kotlinx.serialization, you're building a tree in memory — and any recursive parsing bug you've hit ("why is my nested object null two levels down?") is a tree-traversal bug in disguise.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Decision Trees in On-Device ML
&lt;/h3&gt;

&lt;p&gt;If you've touched ML Kit, TensorFlow Lite, or any on-device recommendation/classification feature, decision trees (and tree-based models like Random Forests) are often doing the heavy lifting behind the prediction.&lt;/p&gt;

&lt;p&gt;So no — this isn't "CS theory you'll never use." You're touching trees every time you open Android Studio.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠️ Building Your First Tree in Kotlin
&lt;/h2&gt;

&lt;p&gt;Let's build a general tree where each node can have multiple children — conceptually similar to how a &lt;code&gt;View&lt;/code&gt; holds a list of child views.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TreeNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;children&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mutableListOf&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TreeNode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;addChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;TreeNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;root&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TreeNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Activity"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;toolbar&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TreeNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Toolbar"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;content&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TreeNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ContentContainer"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;toolbar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;recyclerView&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TreeNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"RecyclerView"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;fab&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TreeNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"FloatingActionButton"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;recyclerView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fab&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Root: ${root.value}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;printTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;printTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;TreeNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;depth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"  "&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;depth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"- ${node.value}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;printTree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;depth&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Output
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Root: Activity
- Activity
  - Toolbar
  - ContentContainer
    - RecyclerView
    - FloatingActionButton
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;printTree&lt;/code&gt; function is a &lt;strong&gt;depth-first traversal&lt;/strong&gt; — the exact same mechanism Android's layout system uses (conceptually) to measure and draw nested views.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚖️ Tree vs Array
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Array&lt;/th&gt;
&lt;th&gt;Tree&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Linear&lt;/td&gt;
&lt;td&gt;Hierarchical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One sequence&lt;/td&gt;
&lt;td&gt;Multiple branches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Index-based access&lt;/td&gt;
&lt;td&gt;Parent-child navigation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for ordered lists&lt;/td&gt;
&lt;td&gt;Best for hierarchical/nested data&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Your &lt;code&gt;RecyclerView&lt;/code&gt; adapter's data source is usually an array or list — but the moment that data has sections, headers, or nested replies, you're modeling a tree and flattening it for display.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✅ Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A Tree organizes data using &lt;strong&gt;parent-child relationships&lt;/strong&gt;, starting from a single &lt;strong&gt;Root&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Nodes can have &lt;strong&gt;multiple children&lt;/strong&gt;; nodes with no children are &lt;strong&gt;Leaf Nodes&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Android is full of trees: the &lt;strong&gt;View hierarchy&lt;/strong&gt;, the &lt;strong&gt;Compose UI tree&lt;/strong&gt;, the &lt;strong&gt;Navigation graph&lt;/strong&gt;, &lt;strong&gt;Room indexes&lt;/strong&gt;, and &lt;strong&gt;JSON responses&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Understanding tree traversal helps you reason about &lt;strong&gt;layout performance&lt;/strong&gt;, &lt;strong&gt;recomposition&lt;/strong&gt;, and &lt;strong&gt;parsing bugs&lt;/strong&gt; — not just interview questions.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚀 What's Next?
&lt;/h2&gt;

&lt;p&gt;This post covers the fundamentals only. In upcoming posts, we'll go deeper into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🌳 Binary Trees &amp;amp; Binary Search Trees (BST)&lt;/li&gt;
&lt;li&gt;🌳 AVL Trees (self-balancing, and why databases love them)&lt;/li&gt;
&lt;li&gt;🌳 Heap Trees (priority queues, scheduling)&lt;/li&gt;
&lt;li&gt;🌳 Tree Traversals — DFS &amp;amp; BFS, and how Compose recomposition relates to them&lt;/li&gt;
&lt;li&gt;🌳 Tries (autocomplete, search suggestions)&lt;/li&gt;
&lt;li&gt;🌳 Segment Trees&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These come up constantly in coding interviews — and, as we just saw, in the Android framework itself.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If this helped connect the dots between DSA and real Android code, follow along for more Kotlin + Android + DSA breakdowns.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  android #kotlin #datastructures #algorithms #beginners
&lt;/h1&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>datastructures</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The Sleeper Announcement from Google I/O 2026 That Will Change How We Think About Apps</title>
      <dc:creator>Vrushali</dc:creator>
      <pubDate>Sun, 24 May 2026 11:35:25 +0000</pubDate>
      <link>https://dev.to/vrushali_dev_15/the-sleeper-announcement-from-google-io-2026-that-will-change-how-we-think-about-apps-1gl6</link>
      <guid>https://dev.to/vrushali_dev_15/the-sleeper-announcement-from-google-io-2026-that-will-change-how-we-think-about-apps-1gl6</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/google-io-writing-2026-05-19"&gt;Google I/O Writing Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Everyone walked away from Google I/O 2026 talking about Compose First, Gemini integrations, and Android 17's adaptive layout push. Fair — those are big. But the announcement I haven't been able to stop thinking about is one that barely got a headline: the &lt;strong&gt;AppFunctions API&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I've been building Android apps for 10 years. I've seen APIs come and go. This one feels different — not because of what it does today, but because of what it signals about what apps are &lt;em&gt;becoming&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What AppFunctions Actually Is
&lt;/h2&gt;

&lt;p&gt;At its core, AppFunctions lets your app expose discrete, named actions directly to AI assistants. Think:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;"Create expense report"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;"Book appointment"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;"Send daily update"&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of a user launching your app, navigating to a screen, tapping through a flow — an agent like Gemini can invoke these actions directly, on the user's behalf, without the app ever coming to the foreground.&lt;/p&gt;

&lt;p&gt;Here's a rough idea of how registering an AppFunction looks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AppFunction&lt;/span&gt;
&lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createExpenseReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppFunctionContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CreateExpenseParams&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;ExpenseResult&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// your business logic here&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ExpenseResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You define the function. You define the parameters. The AI figures out when and how to call it.&lt;/p&gt;


&lt;h2&gt;
  
  
  How to Integrate AppFunctions: A Step-by-Step Example
&lt;/h2&gt;

&lt;p&gt;Let's make this concrete. Here's the full integration from zero to Gemini-callable.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1 — Add the dependency
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// build.gradle.kts (module)&lt;/span&gt;
&lt;span class="nf"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"androidx.appfunctions:appfunctions:1.0.0-alpha01"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;ksp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"androidx.appfunctions:appfunctions-compiler:1.0.0-alpha01"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Step 2 — Define your input/output types
&lt;/h3&gt;

&lt;p&gt;AppFunctions uses typed Kotlin data classes. Keep them serializable — the AI agent needs to construct them from natural language.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Serializable&lt;/span&gt;
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;CreateExpenseParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;  &lt;span class="c1"&gt;// nullable — agent may not always provide this&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@Serializable&lt;/span&gt;
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;ExpenseResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Step 3 — Annotate your function
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;@AppFunction&lt;/code&gt; on a suspend function. The annotation processor generates the registration schema at compile time — no boilerplate XML.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExpenseAppFunctions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ExpenseRepository&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@AppFunction&lt;/span&gt;
    &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createExpenseReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppFunctionContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CreateExpenseParams&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;ExpenseResult&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ExpenseResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Expense created: ${params.title}"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Step 4 — Make it agent-safe (the step everyone skips)
&lt;/h3&gt;

&lt;p&gt;Agents may retry on network failure. Without idempotency, one user voice command could create duplicate records.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AppFunction&lt;/span&gt;
&lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createExpenseReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppFunctionContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CreateExpenseParams&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;ExpenseResult&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Idempotency: return existing record if already created&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;existing&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;existing&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ExpenseResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;existing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Already exists"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ExpenseResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Created"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;Note:&lt;/strong&gt; Use &lt;code&gt;AppFunctionContext.callerPackageName&lt;/code&gt; to scope idempotency keys per agent if you want finer control.&lt;br&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5 — Register in AndroidManifest
&lt;/h3&gt;

&lt;p&gt;Without this, Gemini can't discover your functions at runtime.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- AndroidManifest.xml --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;service&lt;/span&gt;
    &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".ExpenseAppFunctions"&lt;/span&gt;
    &lt;span class="na"&gt;android:exported=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
    &lt;span class="na"&gt;android:permission=&lt;/span&gt;&lt;span class="s"&gt;"android.permission.BIND_APP_FUNCTION_SERVICE"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;intent-filter&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"androidx.appfunctions.AppFunctionService"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/intent-filter&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/service&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Step 6 — What Gemini does with it
&lt;/h3&gt;

&lt;p&gt;Once registered, a user saying &lt;em&gt;"Add a £45 taxi to expenses"&lt;/em&gt; triggers this behind the scenes — no UI, no navigation, no tap:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Gemini constructs and executes this on-device&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;appFunctionManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executeAppFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;targetPackage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"com.yourapp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;functionId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"createExpenseReport"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CreateExpenseParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Taxi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;45.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Transport"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// result.message → "Expense created: Taxi"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's the full loop. Six steps from dependency to agent-callable action — and most of the real work is in steps 3 and 4, not 1 and &lt;/p&gt;


&lt;h2&gt;
  
  
  Why This Is Bigger Than It Sounds
&lt;/h2&gt;

&lt;p&gt;Let me be direct about the mental shift this requires.&lt;/p&gt;

&lt;p&gt;For the last decade, Android apps have been &lt;strong&gt;passive tools&lt;/strong&gt;. A user opens them, interacts with them, closes them. The app waits. The user comes back. That's the model.&lt;/p&gt;

&lt;p&gt;AppFunctions breaks that model entirely.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;Note:&lt;/strong&gt; Your app is no longer just a UI. It's a set of capabilities that can be invoked by an external intelligence — one that operates on the user's behalf, across multiple apps, without requiring explicit navigation.&lt;br&gt;

&lt;/div&gt;



&lt;p&gt;That's not an incremental update. That's a different paradigm.&lt;/p&gt;

&lt;p&gt;Think about what this means for UX assumptions we've held forever:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Onboarding flows designed to guide users? Less relevant if agents bypass them.&lt;/li&gt;
&lt;li&gt;Navigation architecture? Still matters, but it's no longer the &lt;em&gt;only&lt;/em&gt; entry point.&lt;/li&gt;
&lt;li&gt;State management? Now needs to account for actions triggered outside your UI lifecycle.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Part Nobody Is Talking About: What This Demands From Developers
&lt;/h2&gt;

&lt;p&gt;Here's where I think most coverage has dropped the ball.&lt;/p&gt;

&lt;p&gt;Everyone's framing AppFunctions as a feature to "add" to your app. Sprinkle some annotations, expose a few actions, done. But that framing misses the architectural implications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your app logic has to be agent-safe.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Idempotency matters more.&lt;/strong&gt; An agent might call &lt;code&gt;createExpenseReport&lt;/code&gt; twice if a network blip happens. Have you handled that?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error messaging has to be machine-readable.&lt;/strong&gt; If your function fails, the agent needs structured information to recover or report back — not a toast.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permissions and auth need to be explicit.&lt;/strong&gt; An agent acting on a user's behalf still needs to respect scope. You can't just assume ambient user authentication.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is less "add a feature" and more "rethink your service layer."&lt;/p&gt;




&lt;h2&gt;
  
  
  My Honest Take: Exciting, But We're Not Ready
&lt;/h2&gt;

&lt;p&gt;I want to be real here — the Android developer community, broadly, is not prepared for this shift.&lt;/p&gt;

&lt;p&gt;We're still mid-migration to Compose. A lot of teams are still untangling MVVM from spaghetti. And now we're being asked to think about our apps as agent-compatible APIs?&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;Note:&lt;/strong&gt; The gap between "Google announced AppFunctions" and "most production apps expose well-designed AppFunctions" is going to be measured in years, not months. And that's okay — but only if we start thinking about the architecture &lt;em&gt;now&lt;/em&gt;.&lt;br&gt;

&lt;/div&gt;


&lt;p&gt;The developers who will be ahead of this curve are the ones who start treating their business logic as a first-class API today — clean use cases, clear input/output contracts, proper error handling. Not because an agent is calling it yet, but because good architecture pays forward.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I'd Tell My Team Tomorrow
&lt;/h2&gt;

&lt;p&gt;If I were walking into standup tomorrow with one takeaway from I/O 2026, it would be this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start auditing your use cases for agent-readiness.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not to ship AppFunctions next sprint — but to ask: if an AI needed to invoke this action without a human at the keyboard, would our code hold up? Would the error states make sense? Would the auth model work?&lt;/p&gt;

&lt;p&gt;That question alone will surface a lot of architectural debt worth addressing regardless of AppFunctions.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Word on Privacy — Because Someone Has to Say It
&lt;/h2&gt;

&lt;p&gt;I'm excited about AppFunctions. But I'd be doing you a disservice if I didn't flag the privacy surface this opens up.&lt;/p&gt;

&lt;p&gt;When an agent can invoke your app without the user explicitly tapping anything, the consent model gets murky. A few things worth thinking hard about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agents act silently.&lt;/strong&gt; The user said "add a taxi expense" once — they didn't review what data left their device or which systems were touched. Your function needs to do only exactly what it says it does.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sensitive data needs explicit scoping.&lt;/strong&gt; If your AppFunction touches finance, health, or messages, treat the output like a public API response. Return the minimum data needed, nothing more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate callerPackageName.&lt;/strong&gt; &lt;code&gt;AppFunctionContext&lt;/code&gt; gives you the calling agent's package. For sensitive operations, whitelist trusted callers — don't assume all agents deserve equal trust.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log every invocation.&lt;/strong&gt; Users should be able to see what their agent did on their behalf. Build that audit trail from day one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The good news: Android's &lt;code&gt;BIND_APP_FUNCTION_SERVICE&lt;/code&gt; permission means only system-blessed agents like Gemini can invoke your functions by default. The platform guardrails are reasonable. But as the agent ecosystem grows, so does the attack surface.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;Note:&lt;/strong&gt; Treat every &lt;code&gt;@AppFunction&lt;/code&gt; like a public API endpoint — validate inputs, scope outputs, log calls. The annotation is simple; the responsibility it carries is not.&lt;br&gt;

&lt;/div&gt;


&lt;h3&gt;
  
  
  What you're actually exposing
&lt;/h3&gt;

&lt;p&gt;This one surprises developers: you're not exposing source code, but you &lt;em&gt;are&lt;/em&gt; exposing your app's capability surface — and that has its own risks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What AppFunctions reveals to the outside world:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your function names like &lt;code&gt;createExpenseReport&lt;/code&gt; or &lt;code&gt;deleteUserAccount&lt;/code&gt; act as a discoverable public schema — anyone with the right tools can enumerate what your app registers&lt;/li&gt;
&lt;li&gt;Your parameter types reveal your internal data model. The shape of &lt;code&gt;CreateExpenseParams&lt;/code&gt; is visible, not just its name&lt;/li&gt;
&lt;li&gt;Your business logic boundaries — if &lt;code&gt;archiveAllRecords&lt;/code&gt; exists as an AppFunction, you've advertised that capability before you've even shipped the UI for it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Real attack scenarios to think about:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A probing app enumerates your registered functions to reverse-engineer your data model&lt;/li&gt;
&lt;li&gt;An admin-level function without an internal auth check gets invoked by an untrusted agent — the manifest permission alone isn't enough&lt;/li&gt;
&lt;li&gt;Competitors read your function names before a launch and know exactly what's coming&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What to do about it:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Never register a function that wasn't explicitly &lt;em&gt;designed&lt;/em&gt; to be agent-callable — not everything in your repo deserves an &lt;code&gt;@AppFunction&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add auth checks &lt;em&gt;inside&lt;/em&gt; every function, independent of the manifest permission&lt;/li&gt;
&lt;li&gt;Use generic names for sensitive operations where the function name itself leaks intent&lt;/li&gt;
&lt;li&gt;Audit &lt;code&gt;@AppFunction&lt;/code&gt; annotations before every release the same way you'd audit a public REST API&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Google I/O 2026 had plenty of exciting announcements. Compose First is overdue and welcome. The AI dev tooling is genuinely useful. Android Automotive is a real career path worth exploring.&lt;/p&gt;

&lt;p&gt;But AppFunctions is the one that will change what we mean when we say "Android app." It's the sleeper. And five years from now, I think we'll look back at I/O 2026 as the moment the shift began.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How would you handle idempotency in your current service layer if an agent started calling your functions today? Drop your architectural "nightmare" scenarios in the comments — I'd love to hear them.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Relevant session: &lt;a href="https://www.youtube.com/watch?v=aqmpZocmR8o" rel="noopener noreferrer"&gt;Developer Keynote — Google I/O 2026&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>googleiochallenge</category>
      <category>android</category>
      <category>kotlin</category>
    </item>
  </channel>
</rss>
