<?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: Ilbets</title>
    <description>The latest articles on DEV Community by Ilbets (@ilbets).</description>
    <link>https://dev.to/ilbets</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2120061%2F51296e66-3124-4ea1-82be-616b41ba791b.png</url>
      <title>DEV Community: Ilbets</title>
      <link>https://dev.to/ilbets</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ilbets"/>
    <language>en</language>
    <item>
      <title>Your machine has the perfect agentic setup! Use it anytime, anywhere!</title>
      <dc:creator>Ilbets</dc:creator>
      <pubDate>Fri, 13 Mar 2026 14:40:51 +0000</pubDate>
      <link>https://dev.to/ilbets/your-machine-has-the-perfect-agentic-setup-use-it-anytime-anywhere-5b9c</link>
      <guid>https://dev.to/ilbets/your-machine-has-the-perfect-agentic-setup-use-it-anytime-anywhere-5b9c</guid>
      <description>&lt;h2&gt;
  
  
  TaskSquad.ai – talk with agents on your machine, create teams, collaborate, anytime, anywhere
&lt;/h2&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.amazonaws.com%2Fuploads%2Farticles%2F88ardntwcibmzjicfm5c.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.amazonaws.com%2Fuploads%2Farticles%2F88ardntwcibmzjicfm5c.png" alt=" " width="800" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two weeks ago, before going on a long break, I wanted a way to keep using my home AI setup remotely (this was before Claude introduced Remote Control).&lt;/p&gt;

&lt;p&gt;So I hacked a simple app: a daemon running on my Mac that connects to an inbox where I can chat with an agent. I vibecoded the whole thing just in a few hours.&lt;/p&gt;

&lt;p&gt;During my leave, it turned out to be surprisingly convinient. Most of my pet projects already have a CLI + keys environment set up, so agents could deploy things easily. While waiting on the ski lift, I would ask the agent to tweak some UI and redeploy the app. By the next ride up the lift, the change was already live.&lt;/p&gt;

&lt;p&gt;That prototype only supported Gemini, but it made me realize the idea was fun and useful. So after coming back, I kept hacking on it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That’s how &lt;a href="//TaskSquad.ai"&gt;TaskSquad.ai&lt;/a&gt; was born.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;How it works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the portal and create a project&lt;/li&gt;
&lt;/ol&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.amazonaws.com%2Fuploads%2Farticles%2F7qlj9lu5pdfqktd7dkye.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.amazonaws.com%2Fuploads%2Farticles%2F7qlj9lu5pdfqktd7dkye.png" alt=" " width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add agents (one agent per CLI tool + folder path)&lt;/li&gt;
&lt;/ol&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.amazonaws.com%2Fuploads%2Farticles%2F9vor79wg5t6e959rfzz5.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.amazonaws.com%2Fuploads%2Farticles%2F9vor79wg5t6e959rfzz5.png" alt=" " width="800" height="216"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2.1. Add friends to your project*&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.amazonaws.com%2Fuploads%2Farticles%2Fah7klxz5bz8wjbirr9dt.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.amazonaws.com%2Fuploads%2Farticles%2Fah7klxz5bz8wjbirr9dt.png" alt=" " width="800" height="207"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install the daemon on your machine&lt;/li&gt;
&lt;li&gt;Copy the generated agent config into ~/.tasksquad/config.toml&lt;/li&gt;
&lt;li&gt;Login to the tsq daemon&lt;/li&gt;
&lt;/ol&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.amazonaws.com%2Fuploads%2Farticles%2Fci8jymb2xam3kpvtl8lb.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.amazonaws.com%2Fuploads%2Farticles%2Fci8jymb2xam3kpvtl8lb.png" alt=" " width="670" height="766"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run the agent&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Agents currently support CC, OpenCode, and Gemini. _Codex and OpenClaw support is in progress. Once running, you can open the inbox and send tasks to your agents. &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.amazonaws.com%2Fuploads%2Farticles%2Fs50mfjwlq174wvemxipz.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.amazonaws.com%2Fuploads%2Farticles%2Fs50mfjwlq174wvemxipz.png" alt=" " width="800" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The daemon keeps sessions alive, supports multi-round interactions, and lets you preview raw CLI logs.&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.amazonaws.com%2Fuploads%2Farticles%2Fu5q5xdcr4dpo9qm9d9z2.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.amazonaws.com%2Fuploads%2Farticles%2Fu5q5xdcr4dpo9qm9d9z2.png" alt=" " width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can run multiple projects with multiple agents. You can also invite friends and connect their machines to the same team. As well you can also shut it down or reset all sessions from the portal directly.&lt;/p&gt;

&lt;p&gt;This is still an early prototype — feedback and pull requests are welcome!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/xajik/tasksquad" rel="noopener noreferrer"&gt;github.com/xajik/tasksquad&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>openclaw</category>
      <category>openai</category>
    </item>
    <item>
      <title>A New Era of Agent Native Applications</title>
      <dc:creator>Ilbets</dc:creator>
      <pubDate>Sat, 24 May 2025 14:09:31 +0000</pubDate>
      <link>https://dev.to/ilbets/a-new-era-of-agent-native-applications-515n</link>
      <guid>https://dev.to/ilbets/a-new-era-of-agent-native-applications-515n</guid>
      <description>&lt;p&gt;In the next five years, 99% of companies will have agents for their services. That will open up a new world of agent-to-agent communication—an agent economy and even an internet of agents. Agents may not completely replace traditional apps, but they’ll take a huge market share.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Next time you want a new dining table, it might be as simple as asking your Agent app. It’ll message a few store agents, find one you’ll like based on what it knows about you, and place the order.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So, when I started working on Terminal1.app, I wanted to imagine that future. I asked myself what an “AI native” company might look like—and built it, agent-first, from the ground up.&lt;/strong&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.amazonaws.com%2Fuploads%2Farticles%2F7eqgsmofz665r7e41rot.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.amazonaws.com%2Fuploads%2Farticles%2F7eqgsmofz665r7e41rot.png" alt="Terminal1 Logo" width="800" height="195"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Idea
&lt;/h2&gt;

&lt;p&gt;In late 2024, I had a three-hour layover in Munich. I was alone, eating dinner, and thinking about how much time I’d wasted in airports that year. I’d taken around 60 flights for work and leisure. That felt like a lot, but some of my friends, especially those in sales, fly much more.&lt;/p&gt;

&lt;p&gt;I sometimes try to work, code, or read. But let’s be honest — getting anything done in an airport isn’t easy. I started wondering: how many people like me are sitting in airports right now, looking for something meaningful to do?&lt;/p&gt;

&lt;p&gt;That’s when the idea struck me — what if there was something in between Tinder and YC’s Co-Founder Matching to build business connections during travel? An app that connects airport business professionals based on their shared interests in the airport.&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.amazonaws.com%2Fuploads%2Farticles%2Fxde7dv8s9exxmemwp2j8.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.amazonaws.com%2Fuploads%2Farticles%2Fxde7dv8s9exxmemwp2j8.png" alt="Terminal1 Flow" width="800" height="96"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lastly, meaningful social connections are key to personal happiness. I’ve met many people who later became close friends at events and gatherings. Sometimes we’re so busy with work and chores that we forget how important it is to be around people we care about — and who care about us.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terminal 1
&lt;/h2&gt;

&lt;p&gt;Terminal1 connects traveling professionals at airports based on their LinkedIn profiles, flight times, and interests — so they can network while they wait. Transform airport time into business opportunities.&lt;/p&gt;

&lt;p&gt;1️⃣ Log in with LinkedIn to create a profile&lt;/p&gt;

&lt;p&gt;2️⃣ Send your CV to create a detailed profile for matching&lt;/p&gt;

&lt;p&gt;3️⃣ Share your upcoming flight details&lt;/p&gt;

&lt;p&gt;4️⃣ Review and accept your match 24 hours before the flight&lt;/p&gt;

&lt;h2&gt;
  
  
  Communication in the Agentic Era
&lt;/h2&gt;

&lt;p&gt;One thing that changes in the new Agenting Era is how we communicate with customers. You don’t need fancy designs to turn simple user needs into system actions. &lt;strong&gt;Let the agent handle it for you ✨.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The primary communication interface for Terminal1 is email (&lt;em&gt;&lt;strong&gt;&lt;a href="mailto:maya@terminal1.app"&gt;maya@terminal1.app&lt;/a&gt;&lt;/strong&gt;&lt;/em&gt;): send your CV, forward flight tickets, or reach customer support.&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.amazonaws.com%2Fuploads%2Farticles%2F8l62tr5c2468u0a79frq.gif" 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.amazonaws.com%2Fuploads%2Farticles%2F8l62tr5c2468u0a79frq.gif" alt="Terminial1 Maya AI" width="760" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;While there’s also a web interface, it’s intentionally simple, as it’s not necessary in AI-Native app.&lt;/em&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.amazonaws.com%2Fuploads%2Farticles%2Ft8fah0i3dvqxy04pj49e.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.amazonaws.com%2Fuploads%2Farticles%2Ft8fah0i3dvqxy04pj49e.png" alt="Image description" width="800" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;However, I found it useful to address trust issues when working with AI agents.&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  From the 50s to AI Native
&lt;/h2&gt;

&lt;p&gt;From day one, I wanted to build an AI Native system. But first, I had to decide what that really meant for myself. Since agents act like humans, I imagined what Terminal1 would look like as a company built in the 1950s, where everything is handled by people.&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.amazonaws.com%2Fuploads%2Farticles%2Fa1odzz262c1boqz7ueiz.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.amazonaws.com%2Fuploads%2Farticles%2Fa1odzz262c1boqz7ueiz.png" alt="Terminal1 50s" width="800" height="522"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It starts at the reception desk — a scene we all know from old movies. A mailbox, a stack of documents, and a receptionist asking, “How can I help?” They take your request and promise you’ll get a reply by mail in a few days.&lt;/p&gt;

&lt;p&gt;They sort each request into the right box. Later, an assistant with a trolley cruises through the office, delivering each box to the right department. Your CV goes to the CV review team. Your flight tickets go to the flight review team. The matching team checks upcoming flights, compares profiles, and finds a good match. Then they pass it back to the assistant, who brings it to customer support. Finally, customer support sends you a letter by mail about your upcoming meeting on your next flight.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And that is exactly what I did.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Design of the Agentic System
&lt;/h2&gt;

&lt;p&gt;Terminal1 is built around a network of asynchronous agents. Everything starts and ends with an agent. The system is designed to be modular, where each agent focuses on a specific function, passing tasks along a dynamic pipeline.&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.amazonaws.com%2Fuploads%2Farticles%2F0mk74cmf50arvycs9t2f.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.amazonaws.com%2Fuploads%2Farticles%2F0mk74cmf50arvycs9t2f.png" alt="Terminal1 Agents" width="800" height="832"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reception agent — identifies the user’s intent from incoming messages and routes the request to the right agent. It’s the starting point of every interaction.&lt;/li&gt;
&lt;li&gt;Ticket agent — extracts, processes, and organizes flight ticket data such as destinations, dates, and airlines, so it can be used in downstream matching.&lt;/li&gt;
&lt;li&gt;Curriculum Vitae (CV) agent — parses resumes, normalizes the data, and prepares profiles for efficient matching with other users.&lt;/li&gt;
&lt;li&gt;Customer Support (CS) agent — handles incoming support requests, retrieves relevant information, and triggers actions to help the ve user.&lt;/li&gt;
&lt;li&gt;Public Communication agent — generates the final response to the user, translating system output into clear, friendly language.&lt;/li&gt;
&lt;li&gt;Date Interest agent — understanding what the user is looking for in their match: partnership, investment, or job opportunities, etc.&lt;/li&gt;
&lt;li&gt;Date Feedback agent — process feedback from the date&lt;/li&gt;
&lt;li&gt;Matching Agent — create the best possible match for the date&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are also a few other agents that support these main flows, executing essential tasks like data validation, formatting, and cross-checking.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agents
&lt;/h3&gt;

&lt;p&gt;Each agent in the Terminal1 system is built using LangGraph. They interact with the system tools through the MCP, which provides access to databases, matching logic, and communication layers.&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.amazonaws.com%2Fuploads%2Farticles%2Faxjb1aw5k76vorr4d3ev.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.amazonaws.com%2Fuploads%2Farticles%2Faxjb1aw5k76vorr4d3ev.png" alt="Terminal1 Agent" width="800" height="547"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some agents, like the Customer Support agent, are powered by the ReAct framework to support multi-step reasoning and tool calling to resolve more ambiguous or complex requests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prompts
&lt;/h3&gt;

&lt;p&gt;Getting high-quality results from AI agents requires a lot of prompt engineering. Along the way, I learned a few key principles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Order matters — Structure your prompt carefully. Put the most important context upfront.&lt;/li&gt;
&lt;li&gt;Examples — Good prompts need great examples. They guide the model’s behavior better than instructions alone.&lt;/li&gt;
&lt;li&gt;Chain of Drafts (CoD) — An effective technique to improve quality while keeping token usage low. Iterate in stages.&lt;/li&gt;
&lt;li&gt;Models — The same prompt can produce wildly different results across models. Choose your model wisely.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each agent uses a consistent prompt structure:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;Task&amp;gt;&lt;br&gt;
&amp;lt;Examples&amp;gt;&lt;br&gt;
&amp;lt;Customer-Context&amp;gt;&lt;br&gt;
&amp;lt;Real-Time-Context&amp;gt;&lt;br&gt;
&amp;lt;Agent-Identity&amp;gt;&lt;br&gt;
&amp;lt;Company-Identity&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  User Matching Agent
&lt;/h3&gt;

&lt;p&gt;Perhaps the most intriguing part of the system is how we match users. It all starts when someone sends us their CV. The CV agent parses it, extracts key information, and transforms it into a clean, normalized format.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI-normalized profile summaries&lt;/strong&gt; are stored in a vector store. This lets us run similarity searches based on meaningful parameters, not just keywords. The &lt;strong&gt;Date Intent Agent&lt;/strong&gt; does something similar — building an ideal normalized match profile for each user based on their input and context.&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.amazonaws.com%2Fuploads%2Farticles%2Fk0vs5fbge03ci1axq8pt.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.amazonaws.com%2Fuploads%2Farticles%2Fk0vs5fbge03ci1axq8pt.png" alt="Terminal1 vector store" width="800" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The rest of the magic happens in a cron job that runs every few hours. It gets all the unmatched passengers flying in the next 12 hours and groups them by airport. For each airport and overlapping time slot, we will take each potential profile and compute potential candidates based on the “perfect profile”.&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.amazonaws.com%2Fuploads%2Farticles%2Fjqyxnar06w7mygyypi7i.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.amazonaws.com%2Fuploads%2Farticles%2Fjqyxnar06w7mygyypi7i.png" alt="Terminal1 Candidate Mathcing" width="800" height="106"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This matrix, together with users’ profiles and their date intent, will be passed to the Matching Agent to generate final pairs.&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.amazonaws.com%2Fuploads%2Farticles%2F3dt1e1r2dm9tnxclxbdm.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.amazonaws.com%2Fuploads%2Farticles%2F3dt1e1r2dm9tnxclxbdm.png" alt="Terminal1 Candidate Mathcing" width="800" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, everything comes together in a cron job. The heavy lifting — grouping users by location and departure time — is handled by an SQL function for efficiency. The result is then fed to the agent, which processes each user group individually to evaluate and confirm the best possible matches.&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.amazonaws.com%2Fuploads%2Farticles%2F36bq12avkq3lw8cwnfvm.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.amazonaws.com%2Fuploads%2Farticles%2F36bq12avkq3lw8cwnfvm.png" alt="Image description" width="800" height="1238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;`Multi-dimensional matching based on time, location, and customer context is hard. Pair matching is even harder. You need to look at what both people care about and what they offer. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VC looking for an AI startup to invest in and an AI Startup Founder.&lt;/li&gt;
&lt;li&gt;Recruiter from an AI startup and engineering looking for a new opportunity&lt;/li&gt;
&lt;li&gt;Talented singer and music producer
`&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Each match has to be a win-win.&lt;/strong&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.amazonaws.com%2Fuploads%2Farticles%2F2bvoyv2ifiypygsd3icj.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.amazonaws.com%2Fuploads%2Farticles%2F2bvoyv2ifiypygsd3icj.png" alt="Multidimensional matching" width="800" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;With more user feedback, we can build an “Elo score” to help prioritize candidates on very popular destinations.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech Infrastructure
&lt;/h2&gt;

&lt;p&gt;The whole solution is hosted on AWS.&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.amazonaws.com%2Fuploads%2Farticles%2Fohpwf1sgmc617k6y6g60.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.amazonaws.com%2Fuploads%2Farticles%2Fohpwf1sgmc617k6y6g60.png" alt="AWS tech infra" width="800" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tech Cloud
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Originally, I vibe-coded the website with the bolt.new, but I quickly hit its limits. So I downloaded the code and switched to just coding in Cursor.&lt;/em&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.amazonaws.com%2Fuploads%2Farticles%2F0qr0c7tkts3mx6pxanro.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.amazonaws.com%2Fuploads%2Farticles%2F0qr0c7tkts3mx6pxanro.png" alt="Tech Cloud" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Give it a shot
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://terminal1.app/" rel="noopener noreferrer"&gt;Termiminal1.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you have any questions or suggestions, feel free to reach out at:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="mailto:support@terminal1.app"&gt;support@terminal1.app&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>llm</category>
      <category>ai</category>
      <category>startup</category>
      <category>travel</category>
    </item>
    <item>
      <title>Game Night Just Got a Digital Upgrade: The Deck</title>
      <dc:creator>Ilbets</dc:creator>
      <pubDate>Sat, 08 Feb 2025 15:42:49 +0000</pubDate>
      <link>https://dev.to/ilbets/game-night-just-got-a-digital-upgrade-the-deck-67p</link>
      <guid>https://dev.to/ilbets/game-night-just-got-a-digital-upgrade-the-deck-67p</guid>
      <description>&lt;p&gt;&lt;em&gt;The inspiration for “The Deck” came from a situation many of us have experienced. Imagine gathering with friends for a game night, only to realize that nobody has the necessary cards. Frustrating, right? This dilemma sparked the idea of leveraging technology to create a solution.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The primary goal of “The Deck” is to provide a user-friendly and cooperative digital game environment for playing classic games that were usually played with cards on paper. &lt;b&gt; One of the standout features of “The Deck” is its unique ability to assign one device as the “table” (a.k.a. deck).&lt;/b&gt; By placing this device in the middle of the group, all players can witness the real-time state of the cards. This adds a new level of immersion making it a truly captivating experience.&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.amazonaws.com%2Fuploads%2Farticles%2F71nmrse127fyqncho4p3.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2F71nmrse127fyqncho4p3.jpg" alt="Image description" width="712" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Game Flow
&lt;/h3&gt;

&lt;p&gt;First, let's look at the result 👨‍💻. I ideated on what might be the perfect UX for such a solution and settled on the next steps (here we are using Android TV as the table):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create the Room - use TV, mobile, table, or laprot to create a room. &lt;/li&gt;
&lt;/ol&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.amazonaws.com%2Fuploads%2Farticles%2Fo3qfqbma2dp6rbpflluy.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fo3qfqbma2dp6rbpflluy.jpg" alt="Image description" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Join the room. A device that created the room can participate as well, or just be the deck. &lt;/li&gt;
&lt;/ol&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.amazonaws.com%2Fuploads%2Farticles%2Fws77g6wk4sihp9tzvc1t.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fws77g6wk4sihp9tzvc1t.jpg" alt="Image description" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Start the game! As soon as you have enough players, the host can start the game. &lt;/li&gt;
&lt;/ol&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.amazonaws.com%2Fuploads%2Farticles%2Fz21c1z67dw1agl9lsz63.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fz21c1z67dw1agl9lsz63.jpg" alt="Image description" width="800" height="597"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case, TV is the host &amp;amp; deck. Players are using their phones to move and other people can observe game updates on the TV.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementation
&lt;/h3&gt;

&lt;p&gt;Over a span of approximately four months, I dedicated my weekday evenings and weekends to developing three games: Tic Tac Toe, Connect Four, and Dixitt. Eventually, I released them to both iOS and Android stores. Here are some details on the implementation of the game.&lt;/p&gt;

&lt;h4&gt;
  
  
  Transport layer
&lt;/h4&gt;

&lt;p&gt;Considering that I wanted to make sure that app can run in the local network and require bi-directional, low-latency communication between participants, the solution was quite obvious — sockets:&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.amazonaws.com%2Fuploads%2Farticles%2Fxi6x4hjxmdi05q375m4m.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.amazonaws.com%2Fuploads%2Farticles%2Fxi6x4hjxmdi05q375m4m.png" alt="Image description" width="800" height="164"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For MVP I decided to stick to go with socket.io. After a quick search, I found packages for Dart:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pub.dev/packages/socket_io_client" rel="noopener noreferrer"&gt;socket-client&lt;/a&gt;&lt;br&gt;
&lt;a href="https://pub.dev/packages/socket_io" rel="noopener noreferrer"&gt;socket-server&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Game Room
&lt;/h4&gt;

&lt;p&gt;The game room is the platform's base abstraction. Each game starts with a host creating a room and inviting participants and observers. As soon as the game constraints are fulfilled (e.g., the required minimum number of players), the host can start the game.&lt;/p&gt;

&lt;p&gt;Creating architecture was one of the most challenging tasks. As I need to ensure that abstraction will scale well for various games&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.amazonaws.com%2Fuploads%2Farticles%2Fltt46swrzf2up605qst8.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.amazonaws.com%2Fuploads%2Farticles%2Fltt46swrzf2up605qst8.png" alt="Image description" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Components breakdown:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Game Details — it is a description of the Game and room IP. It is advertised in the QR code so clients can check if they support the game and can join;&lt;/li&gt;
&lt;li&gt;Game Room — created based on Game Detail, it is the main orchestrator for the game, keeps track of participants, and controls game state&lt;/li&gt;
&lt;li&gt;Game Participants — List of participants with some metadata&lt;/li&gt;
&lt;li&gt;Participant profile — participant profile in The Deck, with user profile information&lt;/li&gt;
&lt;li&gt;Game Board — base abstraction for any game&lt;/li&gt;
&lt;li&gt;Game Move — board contains a list of all game moves that were applied;&lt;/li&gt;
&lt;li&gt;Game Player — an entity that describes participants' role in the game, like “red” or “yellow” in Connect Four;&lt;/li&gt;
&lt;li&gt;Game Field — representation of the game field, i.e. 7 by 8 matrix for Connect Four;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Room: create, join, start
&lt;/h4&gt;

&lt;p&gt;Here is GameRoom lifetime:&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.amazonaws.com%2Fuploads%2Farticles%2Fzrmssfwa9vf5aggr28eu.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.amazonaws.com%2Fuploads%2Farticles%2Fzrmssfwa9vf5aggr28eu.png" alt="Image description" width="800" height="813"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  The Deck / Table
&lt;/h4&gt;

&lt;p&gt;The deck or table, as well as the client, subscribe to updates, the only difference is that the server cannot execute “move”.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You can play as well without a deck, in case you don’t have a spare device&lt;/em&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.amazonaws.com%2Fuploads%2Farticles%2Fd8jndb0xq1zupl5hsdrx.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.amazonaws.com%2Fuploads%2Farticles%2Fd8jndb0xq1zupl5hsdrx.png" alt="Image description" width="800" height="772"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Please note that Android TV devices serve exclusively as the “table” within the game.&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Packages
&lt;/h4&gt;

&lt;p&gt;From the beginning, I wanted to ensure that socket server code could be run separately and deployed in the cloud. Therefore, I split the app into 4 separate packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Common — shared DTO and utilities&lt;/li&gt;
&lt;li&gt;Server — socket server logic, depends on Common&lt;/li&gt;
&lt;li&gt;Client—socket client logic, depends on Common&lt;/li&gt;
&lt;li&gt;UI — Flutter UI app package, depends on 3 other modules&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.amazonaws.com%2Fuploads%2Farticles%2F9hslzu18x62kcl0a2nyb.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.amazonaws.com%2Fuploads%2Farticles%2F9hslzu18x62kcl0a2nyb.png" alt="Image description" width="800" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Common, Client, and Server modules don’t have any Flutter dependencies and can be published as separate packages.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Using Alfred, I created a new app to run a standalone HTTP server that depends on the Socket Server package and allows you to create a game room, and connect to it via socket. This solution could be potentially deployed in the cloud to remove constrain on the local network.&lt;/p&gt;
&lt;h4&gt;
  
  
  Game State
&lt;/h4&gt;

&lt;p&gt;One tricky part of any online game is to ensure consistency of the game state on all devices. To simplify the problem, I decided that only the server would be able to modify the game state. The client is only able to send a request to change state — move and listen for field updates.&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.amazonaws.com%2Fuploads%2Farticles%2Fkqwtkfunvqtn1zfo2p04.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.amazonaws.com%2Fuploads%2Farticles%2Fkqwtkfunvqtn1zfo2p04.png" alt="Image description" width="800" height="555"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The state is propagated via broadcast ( socket.io API) to all connected clients.&lt;/p&gt;
&lt;h4&gt;
  
  
  UI State with Redux
&lt;/h4&gt;

&lt;p&gt;The client is merely a game field representation, it was quite an obvious decision to use Redux as an application architecture. Each game screen has two basic functions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Draw Game Field&lt;/li&gt;
&lt;li&gt;Send Game Move request&lt;/li&gt;
&lt;/ol&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.amazonaws.com%2Fuploads%2Farticles%2F3tl1t6bf2ys7ix3vq9b1.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.amazonaws.com%2Fuploads%2Farticles%2F3tl1t6bf2ys7ix3vq9b1.png" alt="Image description" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Sockets &amp;amp; Redux
&lt;/h4&gt;

&lt;p&gt;The pieces come together to form the next flow:&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.amazonaws.com%2Fuploads%2Farticles%2Fvuuyv20e0axk4fi9hfkd.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.amazonaws.com%2Fuploads%2Farticles%2Fvuuyv20e0axk4fi9hfkd.png" alt="Image description" width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When the user selects the Game, the app creates a Socket Server &amp;amp; Game Room and stores them on the host device;&lt;/li&gt;
&lt;li&gt;At the same time Host device create a Socket Client and connects to the server running on the same device;&lt;/li&gt;
&lt;li&gt;Socket Server broadcast Game Board to 2 clients (himself and another player);&lt;/li&gt;
&lt;li&gt;Socket client receives a Game Board and propagates it to middleware;&lt;/li&gt;
&lt;li&gt;Middleware update Redux game-specific state;&lt;/li&gt;
&lt;li&gt;Game widget updates based on the new state;&lt;/li&gt;
&lt;li&gt;Now the player can send a &lt;code&gt;move&lt;/code&gt; request to the server, which is propagated via middleware &amp;amp; socket client to the server and GameRoom middleware.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;
  
  
  Socket API
&lt;/h4&gt;

&lt;p&gt;To simplify communication via socket, I decided to build a REST-like abstraction. Each message extends from the back which contains the path. The path is usually a /roomId/* or/roomId/gameId/*. When a client connects to the room, they will subscribe to updates from the specific room for the specific game.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class AppSocketMessage extends JsonEncodeable {
  final String messageId;
  final String path;
  final DateTime createAt;

  final JsonEncodeable data;

  AppSocketMessage.send(this.data, this.path)
      : messageId = Ulid().toUuid(),
        createAt = DateTime.now();

  AppSocketMessage._receive(this.data, this.createAt, this.messageId, this.path);

  @override
  Map&amp;lt;String, dynamic&amp;gt; toMap() {...}

  factory AppSocketMessage.fromJson(Map&amp;lt;String, dynamic&amp;gt; json) {...}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All &lt;code&gt;data&lt;/code&gt; sent in &lt;code&gt;AppSocketMessage&lt;/code&gt; comply with &lt;code&gt;JsonEncodeable&lt;/code&gt; that ensures that it can be converted to JSON.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cross-platform support
&lt;/h3&gt;

&lt;p&gt;A significant benefit of using Flutter is that you can run it on multiple platforms, including Android and iOS. With M1/2 Apple chips supporting iOS apps, you can run The Deck even on your MacBook.&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.amazonaws.com%2Fuploads%2Farticles%2F5atrqit77sqn1hbkirky.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.amazonaws.com%2Fuploads%2Farticles%2F5atrqit77sqn1hbkirky.png" alt="Image description" width="800" height="591"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;➡ Unfortunately, Tizen / Samsung doesn’t allow independent developers to release apps outside of the US. As for Apple TV- this is something I’m planning to look into later.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Design
&lt;/h3&gt;

&lt;p&gt;I want to highlight that all assets in the game, including the app icon, achievement badges, player avatars, and Dixit game cards, everything were generated by Midjourney or DALL-E.  &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.amazonaws.com%2Fuploads%2Farticles%2Fru6ithg7r60lx67z3kv7.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.amazonaws.com%2Fuploads%2Farticles%2Fru6ithg7r60lx67z3kv7.png" alt="Image description" width="800" height="126"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hard to express how much time, effort, and money I saved leveraging generative AI 🧑‍🎨 Even tho, I spend a significant amount of time “fine-tuning” them in Figma.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is next?
&lt;/h3&gt;

&lt;p&gt;First of all, the power of “The Deck” is in the platform. ➡️ Moving forward, my vision is to abstract the game code and open-source it, encouraging enthusiasts to develop and onboard their own games. My goal is to ensure that adding a new game to the platform becomes an effortless process. If you are interested in joining early testing contact me at &lt;strong&gt;&lt;a href="mailto:me@getthedeck.com"&gt;me@getthedeck.com&lt;/a&gt;&lt;/strong&gt; 🤝&lt;/p&gt;

&lt;p&gt;I want to explore new cross-platform connectivity protocols, to allow seamless connection with devices nearby. 🎮&lt;/p&gt;

&lt;p&gt;Add &lt;strong&gt;AI agents&lt;/strong&gt; to play with you when you are lacking a few players 🤖&lt;/p&gt;

&lt;p&gt;Finally, I am intrigued by the prospect of Web3. Give players AI-generated unique NFT badges for achievements, open internal marker place, and incorporate bidding options for adult players with cryptocurrencies. Who knows what exciting developments lie ahead?🤓&lt;/p&gt;

&lt;h3&gt;
  
  
  Visit
&lt;/h3&gt;

&lt;p&gt;Visit &lt;a href="https://getthedeck.com" rel="noopener noreferrer"&gt;getthedeck.com&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.amazonaws.com%2Fuploads%2Farticles%2Fmc0cmgfqvgrnggaj4kvm.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.amazonaws.com%2Fuploads%2Farticles%2Fmc0cmgfqvgrnggaj4kvm.png" alt="Image description" width="800" height="666"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Download
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://play.google.com/store/apps/details?id=com.thedeck.app" rel="noopener noreferrer"&gt;Android&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://apps.apple.com/us/app/the-deck-play/id6448377728" rel="noopener noreferrer"&gt;iOS&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Source Code
&lt;/h3&gt;

&lt;p&gt;Contribution is very welcome! 🤝 ❤️&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Github &lt;a href="https://github.com/xajik/thedeck" rel="noopener noreferrer"&gt;The Deck&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tech Stack
&lt;/h3&gt;

&lt;p&gt;List of tools used to deliver the project&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.amazonaws.com%2Fuploads%2Farticles%2Fp5rddvbaxy5cyaqs6w04.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.amazonaws.com%2Fuploads%2Farticles%2Fp5rddvbaxy5cyaqs6w04.png" alt="Image description" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>flutter</category>
      <category>mobile</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Empower Your Email Routine with LLM Agents: 10X Efficiency Unlocked</title>
      <dc:creator>Ilbets</dc:creator>
      <pubDate>Tue, 24 Sep 2024 14:28:12 +0000</pubDate>
      <link>https://dev.to/ilbets/empower-your-email-routine-with-llm-agents-10x-efficiency-unlocked-4oke</link>
      <guid>https://dev.to/ilbets/empower-your-email-routine-with-llm-agents-10x-efficiency-unlocked-4oke</guid>
      <description>&lt;p&gt;Nowadays, almost every service revolves around communication, whether it’s plumbers, receptionists at clinics, or clerks in banks. Every day, countless people read emails, review attached scanned documents, and PDFs; and sort, organize, and forward them elsewhere. Imagine how much time we could save if we automated this process! With the advancements in Generative AI and Large Language Models (LLMs), it’s no longer just a dream — it’s possible now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem ✨ Solution
&lt;/h2&gt;

&lt;p&gt;You receive an email with a long thread of messages and attached files — many of them with random names. What do you really want? To quickly understand what the email is about and know what actions to take.&lt;/p&gt;

&lt;p&gt;That’s where EmailSnap comes in. Simply forward the email to &lt;a href="mailto:review@emailsnap.app"&gt;review@emailsnap.app&lt;/a&gt;, and EmailSnap will apply AI to analyze the email and its attachments, then send you back a new, actionable, and well-formatted response.&lt;/p&gt;

&lt;p&gt;The processed email contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Title: [Priority] Subject&lt;/li&gt;
&lt;li&gt;From: Sender of the email&lt;/li&gt;
&lt;li&gt;To: Recipient&lt;/li&gt;
&lt;li&gt;Highlights: Key action items in bullet points&lt;/li&gt;
&lt;li&gt;Summary: A concise review of the email content and attached files&lt;/li&gt;
&lt;li&gt;Attachments: Renamed to reflect their actual content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You need to be manually whitelisted to send emails to &lt;a href="mailto:review@emailsnap.app"&gt;review@emailsnap.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Magic, right?🪄 Now, let’s take a look at how it works&lt;/p&gt;

&lt;h2&gt;
  
  
  EmailSnap.app 📩
&lt;/h2&gt;

&lt;p&gt;The implementation consists mainly of two parts: the underlying infrastructure and the LLM flow. Let’s start with the more interesting part.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI Review ✨
&lt;/h3&gt;

&lt;p&gt;For the LLM implementation, we use the LangChain stack: LangChain, and LangSmith. Despite not using LangGraph itself, I apply the same graph-like idea for executing EmailSnap’s LLM processing, as it requires multiple LLM calls with different prompts while using various tools, like saving intermediate states to a database and S3.&lt;/p&gt;

&lt;p&gt;Out execution graph contains the following nodes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Format Email: Reads the EML file and converts it into well-formatted text, handling threads and forwarded messages while removing redundant HTML tags and other irrelevant information.&lt;/li&gt;
&lt;li&gt;Read Attachments: If the attached file is an image or PDF, we convert it to Base64 for the LLM to read the content. For PDFs, each page is converted into a new image, potentially creating a long loop.&lt;/li&gt;
&lt;li&gt;Review Attachment: This node creates a summary with highlights and action items from each document, suggests the recipient, and proposes a better file name.&lt;/li&gt;
&lt;li&gt;Email Summary: The final node combines the formatted email and the summaries from all attachments to generate a complete email with insights, action items, highlights, and an overall summary.
After the final content is generated, we will send out a new email back to the sender including reorganized attachments.&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.amazonaws.com%2Fuploads%2Farticles%2Fcykq86gcag1d2kq02rro.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.amazonaws.com%2Fuploads%2Farticles%2Fcykq86gcag1d2kq02rro.png" alt="AI flow" width="580" height="973"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Infrastructure 🛠️
&lt;/h3&gt;

&lt;p&gt;To process emails, we needed a scalable tech stack, and after a quick search, I found AWS Simple Email Service (SES) to be the perfect solution. The flow works as follows: SES receives an email, stores it in S3, and sends a notification via SNS (Simple Notification Service).&lt;/p&gt;

&lt;p&gt;My service subscribes to an SQS (Simple Queue Service) queue, which listens for SNS messages. From the queue, I retrieve a message ID and use it to load the email from S3. The emails are stored in EML format, which isn’t the easiest to process, but fortunately, there are plenty of libraries to handle that. This setup applies to a specific email address that you register with SNS.&lt;/p&gt;

&lt;p&gt;Below is the most interesting part of the Terraform code to configure it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Setup SNS 

resource "aws_ses_domain_identity" "ses_domain" {
  domain = var.domain
}

resource "aws_sns_topic" "email_notifications" {
  name = "email-notifications"
}

resource "aws_ses_receipt_rule_set" "main" {
  rule_set_name = "default-rule-set"
}

resource "aws_ses_receipt_rule" "email_receipt_rule" {
  rule_set_name = aws_ses_receipt_rule_set.main.rule_set_name
  name          = "store_emails_to_s3_and_notify"

  recipients = ["review@${var.domain}"]

  enabled      = true
  scan_enabled = true


  s3_action {
    bucket_name       = aws_s3_bucket.email_bucket.bucket
    position          = 1
    object_key_prefix = "emails/"
  }

  sns_action {
    topic_arn = aws_sns_topic.email_notifications.arn
    position  = 2
  }
}

# Create SQS 

resource "aws_sqs_queue" "email_queue" {
  name                       = "email-processing-queue"
  visibility_timeout_seconds = 30
  message_retention_seconds  = 86400
}

resource "aws_sns_topic_subscription" "email_sqs_subscription" {
  topic_arn = aws_sns_topic.email_notifications.arn
  protocol  = "sqs"
  endpoint  = aws_sqs_queue.email_queue.arn
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, we subscribe to the queue on the service side to process emails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;while True:
  # Subscribe to the SQS 
  response = sqs_client.receive_message(
      QueueUrl=SNS_QUEUE_URL,
      MessageAttributeNames=['All'],
      MaxNumberOfMessages=5,
      WaitTimeSeconds=20
  )
  messages = response.get('Messages', [])
  for message in messages:
    email_id = get_email_id_from_sns_message(message)
    eml = fetch_email_from_s3(email_id)

# Find email ID from the SQS message
def get_email_id_from_sns_message(message):
    body_string = message.get('Body')
    body_json = json.loads(body_string)
    message_string = body_json.get('Message')
    message_json = json.loads(message_string)
    mail = message_json.get('mail')
    email_id = mail.get('messageId')
    return email_id

# Load and parse Email from EML
def fetch_email_from_s3(email_id: str):
    response = s3_client.get_object(Bucket=EMAIL_BUCKET_NAME, Key=f"emails/{email_id}")    
    body = response['Body'].read()
    return email.message_from_bytes(body,  policy=policy.default)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Besides that, I set up a MySQL RDS and an EC2 instance to run a Dockerized service. I chose this setup for convenience, ease of debugging, and to have more control over the running machine. However, in the long term, it makes more sense to migrate to Fargate for better scalability and management.&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.amazonaws.com%2Fuploads%2Farticles%2Frb3hy1bdws3zqub7lzv5.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.amazonaws.com%2Fuploads%2Farticles%2Frb3hy1bdws3zqub7lzv5.png" alt="Architecture" width="800" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  SES Setup
&lt;/h3&gt;

&lt;p&gt;Setting up a Simple Email Service (SES) requires a few manual steps after provisioning the infrastructure. Once your infrastructure is in place, follow these steps by accessing the SES dashboard:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to Configuration -&amp;gt; Identity -&amp;gt; DKIM and press Generate.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Copy the CNAME records to your domain’s DNS provider.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Add an MX record to your DNS provider with the following details:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Name: Domain&lt;/li&gt;
&lt;li&gt;Mail server: 10 inbound-smtp.us-east-1.amazonaws.com (link changes depending on your region)&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Open Email receiving and activate the rule: default-rule-set.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This setup works in the SES sandbox. To gain production access, you will need to apply for production access from the SES homepage by selecting “Get Production Access.” AWS may require you to justify your use case and potentially ask further questions.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: You can receive emails without the verification process.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample
&lt;/h2&gt;

&lt;p&gt;Finally, let’s take a look at a real example. I took an MRI report in PDF format from an online source, sent it to one email address, and then forwarded it to &lt;a href="mailto:review@emailsnap.app"&gt;review@emailsnap.app&lt;/a&gt;. EmailSnap generated a new subject, highlights, and summary. It also extracted the recipient from the PDF — Dr. Ross Banner — and finally suggested a new file name: Regina Doe MRI Report, based on the patient’s name and procedure.&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.amazonaws.com%2Fuploads%2Farticles%2Fu1dogaqgie0r54igak7w.jpg" 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.amazonaws.com%2Fuploads%2Farticles%2Fu1dogaqgie0r54igak7w.jpg" alt="EmailSnap.app Sample" width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TechStack
&lt;/h2&gt;

&lt;p&gt;Source code: &lt;a href="https://github.com/xajik/emailsnap-service" rel="noopener noreferrer"&gt;https://github.com/xajik/emailsnap-service&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.amazonaws.com%2Fuploads%2Farticles%2F6hhwksskgakue9qwgd5k.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.amazonaws.com%2Fuploads%2Farticles%2F6hhwksskgakue9qwgd5k.png" alt="Emailsnap.app tech stack" width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>llm</category>
      <category>ai</category>
      <category>powerfuldevs</category>
    </item>
  </channel>
</rss>
