<?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: Tushar Vaghela</title>
    <description>The latest articles on DEV Community by Tushar Vaghela (@tusharv).</description>
    <link>https://dev.to/tusharv</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%2F497940%2F9c060091-82af-43b0-828b-9036c268d7ac.jpeg</url>
      <title>DEV Community: Tushar Vaghela</title>
      <link>https://dev.to/tusharv</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tusharv"/>
    <language>en</language>
    <item>
      <title>Hacktoberfest 2026: I Built a Time Machine for My Kids (and Three Other Projects!) 🚀</title>
      <dc:creator>Tushar Vaghela</dc:creator>
      <pubDate>Sat, 31 Oct 2026 14:18:14 +0000</pubDate>
      <link>https://dev.to/tusharv/hacktoberfest-2026-i-built-a-time-machine-for-my-kids-and-three-other-projects-2jdo</link>
      <guid>https://dev.to/tusharv/hacktoberfest-2026-i-built-a-time-machine-for-my-kids-and-three-other-projects-2jdo</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/mlh-hackathon"&gt;MLH x DEV Writing Challenge&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I started programming with BASIC in the 1990s.&lt;/p&gt;

&lt;p&gt;Back then, there was no Stack Overflow, no GitHub Copilot, and definitely no AI writing code for you. Just a blinking cursor, a lot of curiosity, and the excitement of making something work.&lt;/p&gt;

&lt;p&gt;More than 30 years later, I still get excited about building things.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;Hacktoberfest 2026&lt;/strong&gt;, I decided to experiment with &lt;strong&gt;Cursor and OpenAI Codex&lt;/strong&gt; and ended up building four completely different open-source projects.&lt;/p&gt;

&lt;p&gt;One takes you back to 1988. One helps you find a job. One brings BASIC back to life. And one lets you experiment with AI on your own machine.&lt;/p&gt;

&lt;p&gt;Here's what happened.&lt;/p&gt;

&lt;h3&gt;
  
  
  📺 1. 1988.in — A Time Machine for My Kids
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Remember when watching TV meant actually watching whatever was on?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No Netflix. No binge-watching. No recommendations asking, "Because you watched this..."&lt;/p&gt;

&lt;p&gt;You switched on the TV, changed channels, and enjoyed whatever was playing.&lt;/p&gt;

&lt;p&gt;I wanted my kids to experience a little bit of my childhood.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;1988.in&lt;/strong&gt;, a retro television experience that brings back the simplicity of watching TV in the late 1980s.&lt;/p&gt;

&lt;p&gt;What makes it different?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📺 A classic retro television interface.&lt;/li&gt;
&lt;li&gt;📡 Channel surfing instead of scrolling through endless recommendations.&lt;/li&gt;
&lt;li&gt;⏪ No skipping, seeking, or choosing what plays next.&lt;/li&gt;
&lt;li&gt;📱 Your phone can work as a TV remote.&lt;/li&gt;
&lt;li&gt;🕰️ A little time travel, right from your browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;My kids loved their trip to 1988!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That alone made the project worth building.&lt;/p&gt;

&lt;p&gt;But then something unexpected happened.&lt;/p&gt;

&lt;p&gt;When I launched it on Peerlist, I received &lt;strong&gt;9 upvotes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Not 900. Not 90. Just 9. 😄&lt;/p&gt;

&lt;p&gt;I thought that would be the end of the story.&lt;/p&gt;

&lt;p&gt;But today, &lt;strong&gt;1988.in has 1,500+ active users!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And here's the funny part: &lt;strong&gt;I still have no idea how most of them discovered it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Maybe nostalgia has its own recommendation algorithm!&lt;/p&gt;

&lt;p&gt;It reminded me that sometimes the number of people using what you build matters far more than the number of people applauding its launch.&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href="https://www.1988.in/watch" rel="noopener noreferrer"&gt;Travel to 1988&lt;/a&gt;&lt;/strong&gt; | &lt;a href="https://github.com/tusharv/positive-player" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  💼 2. Job Ready — Your Resume Doesn't Need Fiction
&lt;/h3&gt;

&lt;p&gt;We've all seen AI tools promising to make resumes "10x better."&lt;/p&gt;

&lt;p&gt;But what does that mean? Adding skills you've never used? Turning a small contribution into "led an enterprise-wide transformation"?&lt;/p&gt;

&lt;p&gt;I wanted something different.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Job Ready&lt;/strong&gt; helps candidates understand how well their actual experience matches a job description.&lt;/p&gt;

&lt;p&gt;It helps you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Upload your resume and compare it with a job description.&lt;/li&gt;
&lt;li&gt;Identify matching skills and missing requirements.&lt;/li&gt;
&lt;li&gt;Understand where you're a strong fit.&lt;/li&gt;
&lt;li&gt;Improve how your real experience is presented.&lt;/li&gt;
&lt;li&gt;Discover what to learn to become a better candidate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The philosophy behind the project is simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use AI to explain your experience better, not invent a career you never had.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href="https://jobready.tech/" rel="noopener noreferrer"&gt;Try Job Ready&lt;/a&gt;&lt;/strong&gt; | &lt;a href="https://github.com/tusharv/green-grass" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  👻 3. Ghost BASIC — Hello, Old Friend!
&lt;/h3&gt;

&lt;p&gt;My programming journey started with BASIC.&lt;/p&gt;

&lt;p&gt;If you remember writing something like this, we probably belong to the same generation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10 PRINT "HELLO, WORLD!"
20 GOTO 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And yes, we've all written an infinite loop at least once. 😄&lt;/p&gt;

&lt;p&gt;For Hacktoberfest, I wanted to bring back that experience.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Ghost BASIC&lt;/strong&gt;, a Python-based terminal application inspired by the good old GW-BASIC and QBASIC.&lt;/p&gt;

&lt;p&gt;It includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Classic line-numbered BASIC programming.&lt;/li&gt;
&lt;li&gt;Loops, conditions, arrays, and subroutines.&lt;/li&gt;
&lt;li&gt;A terminal-based programming environment.&lt;/li&gt;
&lt;li&gt;Built-in examples and documentation.&lt;/li&gt;
&lt;li&gt;Optional AI assistance using Ollama for debugging and explaining code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The idea is to combine the simplicity of old-school programming with modern developer tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thirty years later, BASIC still makes me smile.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href="https://tusharv.github.io/GBASIC/" rel="noopener noreferrer"&gt;Explore Ghost BASIC&lt;/a&gt;&lt;/strong&gt; | &lt;a href="https://github.com/tusharv/GBASIC" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🤖 4. Local LLM Studio — Your AI, Your Machine
&lt;/h3&gt;

&lt;p&gt;Everyone is talking about AI. But why should every experiment require a cloud API?&lt;/p&gt;

&lt;p&gt;With Ollama, LM Studio, and llama.cpp, we can run language models locally.&lt;/p&gt;

&lt;p&gt;The challenge is making the experience simple enough for anyone to explore.&lt;/p&gt;

&lt;p&gt;That's why I built &lt;strong&gt;Local LLM Studio&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It lets you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chat with models running on your computer.&lt;/li&gt;
&lt;li&gt;Connect to Ollama, LM Studio, and compatible local model servers.&lt;/li&gt;
&lt;li&gt;Discover available models.&lt;/li&gt;
&lt;li&gt;Compare model response speeds.&lt;/li&gt;
&lt;li&gt;Keep conversations stored locally.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's designed to make local AI experimentation easier, without requiring developers to build their own interface from scratch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sometimes the most interesting AI experiments happen without sending everything to the cloud.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href="https://tusharv.github.io/local-llm/" rel="noopener noreferrer"&gt;Explore Local LLM Studio&lt;/a&gt;&lt;/strong&gt; | &lt;a href="https://github.com/tusharv/local-llm" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Four projects, four different experiments, and plenty of lessons learned.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Project&lt;/th&gt;
&lt;th&gt;Demo / Showcase&lt;/th&gt;
&lt;th&gt;Source Code&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;📺 1988.in&lt;/td&gt;
&lt;td&gt;&lt;a href="https://www.1988.in/watch" rel="noopener noreferrer"&gt;Time Travel&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/tusharv/positive-player" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;💼 Job Ready&lt;/td&gt;
&lt;td&gt;&lt;a href="https://jobready.tech/" rel="noopener noreferrer"&gt;Try It&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/tusharv/green-grass" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;👻 Ghost BASIC&lt;/td&gt;
&lt;td&gt;&lt;a href="https://tusharv.github.io/GBASIC/" rel="noopener noreferrer"&gt;Explore&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/tusharv/GBASIC" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🤖 Local LLM Studio&lt;/td&gt;
&lt;td&gt;&lt;a href="https://tusharv.github.io/local-llm/" rel="noopener noreferrer"&gt;Explore&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/tusharv/local-llm" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All four projects are open source. Feel free to explore, raise issues, or contribute.&lt;/p&gt;

&lt;h2&gt;
  
  
  Partner Technologies
&lt;/h2&gt;

&lt;p&gt;One of the fun parts of Hacktoberfest was experimenting with different tools and services to turn weekend ideas into working projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  💰 $50 Hosting Render Credits — From Localhost to Live
&lt;/h3&gt;

&lt;p&gt;I used &lt;strong&gt;$50 in hosting Render credits&lt;/strong&gt; to deploy Job Ready.&lt;/p&gt;

&lt;p&gt;Instead of keeping the project running only on my laptop, I could make it publicly accessible at &lt;a href="https://jobready.tech/" rel="noopener noreferrer"&gt;jobready.tech&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For an experimental open-source project, credits like these are especially useful. They let you focus on building and testing ideas rather than immediately worrying about infrastructure expenses.&lt;/p&gt;

&lt;h3&gt;
  
  
  🌐 Get.Tech — A Free Domain for Job Ready
&lt;/h3&gt;

&lt;p&gt;Thanks to &lt;a href="https://get.tech/" rel="noopener noreferrer"&gt;Get.Tech&lt;/a&gt;, I got a &lt;strong&gt;free .tech domain&lt;/strong&gt; for Job Ready.&lt;/p&gt;

&lt;p&gt;There's something satisfying about seeing your project running on its own domain instead of localhost.&lt;/p&gt;

&lt;p&gt;From an idea to &lt;strong&gt;jobready.tech&lt;/strong&gt;!&lt;/p&gt;

&lt;h3&gt;
  
  
  🦙 Ollama — AI Across Three Projects
&lt;/h3&gt;

&lt;p&gt;Ollama became part of three of my Hacktoberfest experiments.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Job Ready:&lt;/strong&gt; Integrating AI capabilities for resume analysis and improvement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ghost BASIC:&lt;/strong&gt; Adding optional AI-powered debugging and code explanations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local LLM Studio:&lt;/strong&gt; Connecting to locally hosted language models and experimenting with different inference setups.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What I enjoyed most about Ollama was the ability to experiment with AI without making every feature dependent on a paid cloud API.&lt;/p&gt;

&lt;p&gt;It also opened up interesting possibilities around privacy, local development, and developer-controlled AI infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  💻 Cursor + OpenAI Codex — My AI Coding Companions
&lt;/h3&gt;

&lt;p&gt;I used &lt;strong&gt;Cursor and OpenAI Codex&lt;/strong&gt; throughout these four projects.&lt;/p&gt;

&lt;p&gt;The experience was fascinating.&lt;/p&gt;

&lt;p&gt;An idea that previously required considerable setup and boilerplate could now become a working prototype much faster.&lt;/p&gt;

&lt;p&gt;But there was an equally important lesson.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI is very good at writing code. That doesn't mean every line it writes is good code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You still need to make architectural decisions, understand the output, debug unexpected behavior, and review what you're shipping.&lt;/p&gt;

&lt;p&gt;For me, these tools didn't replace programming. They gave me more freedom to experiment.&lt;/p&gt;

&lt;p&gt;And that was exactly what I wanted from Hacktoberfest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hackathon Experience
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🎃 Hacktoberfest 2026 — Just Build Something!
&lt;/h3&gt;

&lt;p&gt;Most of my professional work involves engineering leadership, system architecture, delivery planning, and working with teams building large-scale applications.&lt;/p&gt;

&lt;p&gt;But sometimes, I miss simply opening an editor and building something for no other reason than curiosity.&lt;/p&gt;

&lt;p&gt;Hacktoberfest gave me that opportunity.&lt;/p&gt;

&lt;p&gt;There were no client requirements or product roadmaps driving these four experiments.&lt;/p&gt;

&lt;p&gt;Just ideas I wanted to explore.&lt;/p&gt;

&lt;p&gt;And the variety made it even more enjoyable.&lt;/p&gt;

&lt;p&gt;One project took me back to childhood television. Another tackled a real problem in job hunting. A third brought back my first programming language. And the fourth let me explore the world of local AI.&lt;/p&gt;

&lt;h3&gt;
  
  
  ❤️ What I'll Remember Most
&lt;/h3&gt;

&lt;p&gt;Of all four projects, &lt;strong&gt;1988.in is closest to my heart.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I didn't build it to start a company or solve a big industry problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I built it for my kids.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I wanted them to experience something from my childhood, when watching TV was about discovering what was playing rather than deciding what to watch.&lt;/p&gt;

&lt;p&gt;And watching them enjoy their little time-travel experience was priceless.&lt;/p&gt;

&lt;p&gt;The 1,500+ active users were an unexpected bonus.&lt;/p&gt;

&lt;p&gt;Especially considering those 9 Peerlist upvotes! 😄&lt;/p&gt;

&lt;p&gt;I still don't know how everyone found the project, but I'm happy they did.&lt;/p&gt;

&lt;p&gt;Maybe the best projects aren't always the ones with elaborate business plans or complicated technology.&lt;/p&gt;

&lt;p&gt;Sometimes, they're the ones built out of curiosity, memories, and a little bit of love.&lt;/p&gt;

&lt;p&gt;I started programming more than 30 years ago because seeing something come alive on a screen felt magical.&lt;/p&gt;

&lt;p&gt;Today, I have Cursor, Codex, Ollama, and technologies I couldn't have imagined back then.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The tools have changed. The joy of building hasn't.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And that's what I'll remember about Hacktoberfest 2026.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep learning. Keep experimenting. Keep building. 🚀&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Happy Hacktoberfest! 🎃&lt;/p&gt;




&lt;h1&gt;
  
  
  hacktoberfest #opensource #devchallenge #mlh #buildinpublic #cursor #codex #ollama
&lt;/h1&gt;

</description>
      <category>mlhacks</category>
      <category>devchallenge</category>
      <category>hackathon</category>
    </item>
    <item>
      <title>Ghost BASIC: the dead language still runs, and Gemma has to learn its dialect</title>
      <dc:creator>Tushar Vaghela</dc:creator>
      <pubDate>Tue, 27 Oct 2026 16:34:29 +0000</pubDate>
      <link>https://dev.to/tusharv/ghost-basic-the-dead-language-still-runs-and-gemma-has-to-learn-its-dialect-2gb2</link>
      <guid>https://dev.to/tusharv/ghost-basic-the-dead-language-still-runs-and-gemma-has-to-learn-its-dialect-2gb2</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week4-2026-10-26"&gt;Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Ghost BASIC&lt;/strong&gt; is a small BASIC environment you run in a terminal. The ghost is the language.&lt;/p&gt;

&lt;p&gt;Numbered BASIC is the dialect people met in school computer labs: line numbers, &lt;code&gt;FOR&lt;/code&gt;/&lt;code&gt;NEXT&lt;/code&gt;, &lt;code&gt;PRINT&lt;/code&gt;, a program that fit on one screen. Those machines are gone. The programs are not. Ghost BASIC loads a &lt;code&gt;.bas&lt;/code&gt; file, including old DOS text, and runs it. Press F5 and it prints. Press F1 and it opens an offline reference for the dialect it actually implements.&lt;/p&gt;

&lt;p&gt;Week 4 asked for something spooky, or something that keeps a memory alive. I took the second reading. The first one is painted on the splash screen: an ASCII ghost crosses the terminal, then gets out of the way. What remains is an editor.&lt;/p&gt;

&lt;p&gt;Code Magic, on F8, is the optional companion. It can debug, explain, write, or suggest. The default model is &lt;strong&gt;Gemma 4 31B&lt;/strong&gt; (&lt;code&gt;gemma4:31b&lt;/code&gt;) through Ollama Cloud. It does not get to invent a richer BASIC than the one on the left. A proposal is compiled locally, and applied only after you review the diff.&lt;/p&gt;

&lt;p&gt;Many entries this week put a spirit in the shell. &lt;a href="https://dev.to/sansk_ya/seance-an-offline-seance-with-the-ghost-of-algol-60-56km"&gt;An offline séance with ALGOL 60&lt;/a&gt; keeps a dead language honest by refusing to let the model speak past a curated record. Ghost BASIC is the other half of that idea: the language is executable again, and the model has to write something the runtime will accept.&lt;/p&gt;

&lt;p&gt;This is a numbered-BASIC subset, not a finished GW-BASIC or QBasic. QBasic procedures can be opened and read. They cannot run yet.&lt;/p&gt;

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

&lt;p&gt;Ghost BASIC is a terminal program, so the live site is a tour with real screenshots, not a hosted interpreter:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://tusharv.github.io/GBASIC/" rel="noopener noreferrer"&gt;https://tusharv.github.io/GBASIC/&lt;/a&gt;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F44a9t6ihswzy618lz8ib.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%2F44a9t6ihswzy618lz8ib.png" alt="Startup splash" width="800" height="546"&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%2Fhjv3nlbtclxwnswcu7u1.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%2Fhjv3nlbtclxwnswcu7u1.png" alt="Editor running a pyramid example" width="800" height="546"&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%2Fk8g9lx6b99850rdcvio8.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%2Fk8g9lx6b99850rdcvio8.png" alt="Code Magic beside the program" width="800" height="546"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Python 3.12 or newer. No account for the editor, the examples, F1 help, or Run. Code Magic asks for your own Ollama Cloud key the first time you open it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/tusharv/GBASIC.git
&lt;span class="nb"&gt;cd &lt;/span&gt;GBASIC
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
python &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'.[dev]'&lt;/span&gt;
GBASIC
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then F3, choose &lt;code&gt;fibonacci.bas&lt;/code&gt;, F5. Answers to &lt;code&gt;INPUT&lt;/code&gt; go in the bottom field. F6 stops a run. &lt;code&gt;GBASIC --no-splash&lt;/code&gt; skips the ghost.&lt;/p&gt;

&lt;p&gt;The syntax check around Magic is tested with an in-process stand-in for the HTTP call. I did not have an Ollama key in the build environment, so a live model reply is something you will see with your own key. I am not pasting one here as a recorded run.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;MIT licensed. The interpreter does not phone home. Magic contacts the network only when you press Send.&lt;/p&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/tusharv" rel="noopener noreferrer"&gt;
        tusharv
      &lt;/a&gt; / &lt;a href="https://github.com/tusharv/GBASIC" rel="noopener noreferrer"&gt;
        GBASIC
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Ghost Basic - Python based version of classic QBASIC
    &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;Ghost BASIC&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;An independent MIT-licensed BASIC environment for Python 3.12+. Version 0.4 includes a
full-screen ASCII terminal editor, searchable keyword help, a tested BASIC interpreter
and optional &lt;strong&gt;Code Magic&lt;/strong&gt; powered by Ollama Cloud
It is &lt;strong&gt;not yet a complete GW-BASIC or QBasic implementation&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Screenshots&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Real captures of the running terminal application. The ghost moves in the app; its image
below shows one frame of the startup animation.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Editor and program output&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tusharv/GBASIC/site/assets/screenshots/editor.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%2Ftusharv%2FGBASIC%2FHEAD%2Fsite%2Fassets%2Fscreenshots%2Feditor.png" alt="Ghost BASIC editor running the pyramid example"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Startup splash and flying ghost&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tusharv/GBASIC/site/assets/screenshots/splash.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%2Ftusharv%2FGBASIC%2FHEAD%2Fsite%2Fassets%2Fscreenshots%2Fsplash.png" alt="Ghost BASIC splash screen with the ASCII ghost"&gt;&lt;/a&gt;&lt;/p&gt;

See the examples picker and keyword help
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tusharv/GBASIC/site/assets/screenshots/examples.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%2Ftusharv%2FGBASIC%2FHEAD%2Fsite%2Fassets%2Fscreenshots%2Fexamples.png" alt="Open dialog with the examples dropdown expanded"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/tusharv/GBASIC/site/assets/screenshots/help.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%2Ftusharv%2FGBASIC%2FHEAD%2Fsite%2Fassets%2Fscreenshots%2Fhelp.png" alt="Searchable keyword reference displaying FOR loop help"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Visit the &lt;a href="https://tusharv.github.io/GBASIC/" rel="nofollow noopener noreferrer"&gt;Ghost BASIC website&lt;/a&gt;.
The &lt;a href="https://github.com/tusharv/GBASIC/site/index.html" rel="noopener noreferrer"&gt;landing page source&lt;/a&gt; and &lt;a href="https://github.com/tusharv/GBASIC/docs/GITHUB_PAGES.md" rel="noopener noreferrer"&gt;GitHub Pages deployment guide&lt;/a&gt;
are included in this repository.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Launch the terminal UI&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;After installation and activating the environment, launch from the project folder with:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;GBASIC&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The package installs both &lt;code&gt;GBASIC&lt;/code&gt; and &lt;code&gt;ghost-basic&lt;/code&gt; commands. You can also launch directly
with &lt;code&gt;.venv/bin/GBASIC&lt;/code&gt; (Windows: &lt;code&gt;.venv\Scripts\GBASIC.exe&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;A startup splash displays &lt;strong&gt;Ghost BASIC&lt;/strong&gt; with a flying ASCII ghost…&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/tusharv/GBASIC" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;examples/fibonacci.bas&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10 A=0: B=1
20 FOR I=1 TO 10
30 PRINT A;
40 T=A+B: A=B: B=T
50 NEXT I
60 PRINT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The editor, the runtime, and the 175-topic help stay on the machine. Send is the only arrow that leaves: one fenced program comes back, the local compiler checks it, and you apply the diff yourself.&lt;/p&gt;

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

&lt;p&gt;Ghost BASIC is Python 3.12. The terminal UI is &lt;a href="https://github.com/Textualize/textual" rel="noopener noreferrer"&gt;Textual&lt;/a&gt;. Execution, file loading, and help need no model and no network. Help covers 175 topics, and anything not implemented is marked that way.&lt;/p&gt;

&lt;p&gt;Old files are part of the point. Open accepts UTF-8 and falls back to DOS CP437, including box-drawing characters and a trailing Ctrl+Z. Save writes UTF-8 and does not rewrite the original just because you opened it.&lt;/p&gt;

&lt;p&gt;Code Magic calls Ollama's chat endpoint. The default model name is &lt;code&gt;gemma4:31b&lt;/code&gt;. You can type another Cloud model name. The key is stored in the OS credential vault (macOS Keychain, Windows Credential Locker, or a Linux secret service), not in a project file.&lt;/p&gt;

&lt;p&gt;The model has no shell, no filesystem, and no permission to run the program. Each Send can include the open filename (not the folder), the source, and the last 6,000 characters of that run's output. Turn Context off and those stay behind. The prompt lists the implemented statements and tells the model not to invent &lt;code&gt;RND&lt;/code&gt;, procedures, or graphics.&lt;/p&gt;

&lt;p&gt;If the reply contains exactly one &lt;code&gt;basic&lt;/code&gt; fence, Ghost BASIC compiles that source and does not execute it. A syntax error triggers one correction request. A second failure is shown to you. Apply appears only after you open the diff. Ctrl+Z undoes it. F5 is how you learn whether the program does what you asked. A clean compile is not proof of behavior.&lt;/p&gt;

&lt;p&gt;That constraint is the project. A general model will happily write QBasic. Ghost BASIC cannot run QBasic procedures. The interesting failure is a fluent program the interpreter rejects.&lt;/p&gt;

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

&lt;p&gt;A closed chat API could explain a &lt;code&gt;FOR&lt;/code&gt; loop. It could not be the language.&lt;/p&gt;

&lt;p&gt;The interpreter, the help, and the examples stay on the machine. A classroom or a folder of old &lt;code&gt;.bas&lt;/code&gt; files does not need an account. If the model host disappears, &lt;code&gt;PRINT&lt;/code&gt; still prints. That is the part a closed API cannot offer: the artifact outlives the service.&lt;/p&gt;

&lt;p&gt;Magic does use a service, and that limit should be plain. It needs a network and an Ollama Cloud account. It does not run with the cable pulled. What the open-weight model changes is the contract around that call:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The default brain is Gemma, named in settings as &lt;code&gt;gemma4:31b&lt;/code&gt;. Swapping the model name does not mean rewriting the interpreter.&lt;/li&gt;
&lt;li&gt;The dialect rules live next to the compiler that enforces them. A vendor cannot silently widen BASIC with features this runtime does not have. The local check sends those answers back.&lt;/li&gt;
&lt;li&gt;You can read the prompt, the size limits, and the one-correction rule. Apply is a diff against the editor, not a hidden write.&lt;/li&gt;
&lt;li&gt;Only the open buffer and a slice of output go out, and only when you press Send.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A closed assistant would still draw a triangle of asterisks. It would also be free to describe a language I did not build. Here the language is the repository. The model is a guest that has to pass the compiler.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Spirit of It
&lt;/h2&gt;

&lt;p&gt;The splash ghost is a joke that lasts a few seconds. The part that stayed is quieter.&lt;/p&gt;

&lt;p&gt;Open a file saved on a DOS machine. The line endings are wrong for a modern editor, the box-drawing characters are in CP437, and the file may end with the Ctrl+Z those programs used as an end mark. Ghost BASIC reads it, leaves the original bytes on disk, and shows numbered lines you can run.&lt;/p&gt;

&lt;p&gt;That is the offering. Not a story about the person who typed &lt;code&gt;10 PRINT&lt;/code&gt;. The program itself, still willing to print.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma.&lt;/strong&gt; Code Magic defaults to &lt;code&gt;gemma4:31b&lt;/code&gt; on Ollama Cloud. The prompt, the one-shot syntax repair, and the apply path are built around that open-weight model, and the name can be changed. Inference is hosted. This is not a local Gemma runtime.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>hf26challenge</category>
      <category>gemma</category>
      <category>python</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Local LLM Studio: chat and a speed check that stay on the laptop</title>
      <dc:creator>Tushar Vaghela</dc:creator>
      <pubDate>Sat, 24 Oct 2026 19:18:41 +0000</pubDate>
      <link>https://dev.to/tusharv/local-llm-studio-chat-and-a-speed-check-that-stay-on-the-laptop-5a5</link>
      <guid>https://dev.to/tusharv/local-llm-studio-chat-and-a-speed-check-that-stay-on-the-laptop-5a5</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026-10-19"&gt;Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I wanted a local model for the boring stuff: drafting a reply I do not want in someone else's log, checking whether a screenshot is readable, and finding out if a 3B model is actually usable on this laptop. What I had instead was three apps, three ports, and a terminal I had to babysit.&lt;/p&gt;

&lt;p&gt;Local LLM Studio is the slow version of that workflow. It sits on &lt;code&gt;127.0.0.1&lt;/code&gt; and talks to whatever open model server is already running.&lt;/p&gt;

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

&lt;p&gt;Local LLM Studio is a small private front end for a model server on your own machine. It speaks the OpenAI-compatible &lt;code&gt;/v1&lt;/code&gt; API, so the same install works with &lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;, &lt;a href="https://lmstudio.ai" rel="noopener noreferrer"&gt;LM Studio&lt;/a&gt;, and &lt;a href="https://github.com/ggml-org/llama.cpp" rel="noopener noreferrer"&gt;llama.cpp&lt;/a&gt;'s &lt;code&gt;llama-server&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Four jobs, and then it gets out of the way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Setup&lt;/strong&gt; tells you whether the saved server answers, and prints the install and start commands for macOS, Windows, or Linux. You copy those commands into a terminal yourself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chat&lt;/strong&gt; streams a reply and reloads the same transcript after a refresh. Image attach shows up only when that model is marked as able to see.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Models&lt;/strong&gt; lists whatever &lt;code&gt;GET /v1/models&lt;/code&gt; returns. On Ollama it can also pull a model, delete one, and read the native vision flag. Pull and delete stay hidden for LM Studio and llama.cpp, because those runtimes load weights themselves.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Benchmarks&lt;/strong&gt; run one model at a time and record time to first token and tokens per second for &lt;em&gt;this&lt;/em&gt; server and &lt;em&gt;this&lt;/em&gt; tokenizer. A discarded warmup is on by default, because the first sample is mostly the runtime loading weights.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The person who gets to be lazier is anyone who keeps a local model around for private drafts and then loses twenty minutes remembering which port is which. Studio binds to &lt;code&gt;127.0.0.1:8000&lt;/code&gt;. Chats, uploaded images, and benchmark rows stay in a &lt;code&gt;./data&lt;/code&gt; folder next to the app. There is no account and no telemetry.&lt;/p&gt;

&lt;p&gt;A loopback server URL is saved immediately. A private-network URL is saved only after you confirm it, because the prompt then leaves the machine. Public cloud hosts, including &lt;code&gt;https://api.openai.com/v1&lt;/code&gt;, are rejected.&lt;/p&gt;

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

&lt;p&gt;There is no deployed link, and that is the product. Studio listens only on loopback, and the URL check turns a public host away.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python -m pip install -e ".[dev]"
cd web &amp;amp;&amp;amp; npm install &amp;amp;&amp;amp; npm run build &amp;amp;&amp;amp; cd ..
python -m studio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Open &lt;code&gt;http://127.0.0.1:8000&lt;/code&gt;. On Windows, &lt;code&gt;localhost&lt;/code&gt; often resolves to IPv6 while Studio listens on IPv4, so use the numeric address.&lt;/p&gt;
&lt;h3&gt;
  
  
  Setup
&lt;/h3&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%2Fdll1o3xrlvdzndpt478f.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%2Fdll1o3xrlvdzndpt478f.png" alt=" " width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Benchmark
&lt;/h3&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%2F9h3aao18q59i1ewc9vxv.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%2F9h3aao18q59i1ewc9vxv.png" alt=" " width="800" height="487"&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%2Fqlm7a32vln36ozfkgpo4.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%2Fqlm7a32vln36ozfkgpo4.png" alt=" " width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Chat
&lt;/h3&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%2F202x32wcp5572pbqirrp.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%2F202x32wcp5572pbqirrp.png" alt=" " width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;MIT licensed. The repo is &lt;a href="https://github.com/tusharv/local-llm" rel="noopener noreferrer"&gt;tusharv/local-llm&lt;/a&gt;.&lt;/p&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/tusharv" rel="noopener noreferrer"&gt;
        tusharv
      &lt;/a&gt; / &lt;a href="https://github.com/tusharv/local-llm" rel="noopener noreferrer"&gt;
        local-llm
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Tool to Setup and Run LLM Locally
    &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;Local LLM Studio&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;Local LLM Studio is a private chat, model list, vision check, and speed benchmark for a model server running on your own machine. It speaks the OpenAI-compatible &lt;code&gt;/v1&lt;/code&gt; API, so it works with Ollama, LM Studio, llama.cpp, and any other local server that implements those routes. Ollama is a preset that can also pull a model, delete a model, and read native vision flags.&lt;/p&gt;

&lt;p&gt;Studio binds to &lt;code&gt;127.0.0.1:8000&lt;/code&gt;. Chats, images, and benchmark rows stay in &lt;code&gt;./data&lt;/code&gt;. It does not install or start Ollama, LM Studio, or llama.cpp. The first run prints the commands for your operating system. You copy them into a terminal yourself.&lt;/p&gt;

&lt;p&gt;The same Studio install is used on macOS, Windows, and Linux.&lt;/p&gt;

&lt;p&gt;A plain explanation of why Studio exists, and who it is for, is at &lt;a href="https://tusharv.github.io/local-llm/" rel="nofollow noopener noreferrer"&gt;https://tusharv.github.io/local-llm/&lt;/a&gt;.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Install Studio&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;You need Python 3.11 or newer and Node.js 20 or newer.&lt;/p&gt;

&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;
&lt;pre class="notranslate"&gt;&lt;code&gt;python&lt;/code&gt;&lt;/pre&gt;…&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tusharv/local-llm" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;The privacy claim is a URL check in &lt;code&gt;studio/url_policy.py&lt;/code&gt;. Loopback is saved immediately. A private LAN address needs an explicit confirm, because the prompt then leaves the machine. A public host is refused and the database is left unchanged.&lt;/p&gt;

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

&lt;p&gt;The open-source AI in this project is the model server, not an agent framework. Studio ships no weights. It assumes you already run an open-weight model through one of three local runtimes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Server&lt;/th&gt;
&lt;th&gt;URL you save&lt;/th&gt;
&lt;th&gt;What Studio may do&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ollama&lt;/td&gt;
&lt;td&gt;&lt;code&gt;http://127.0.0.1:11434/v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Chat, list, pull, delete, read vision capability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LM Studio&lt;/td&gt;
&lt;td&gt;&lt;code&gt;http://127.0.0.1:1234/v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Chat and list. Load the model in LM Studio.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;llama.cpp&lt;/td&gt;
&lt;td&gt;&lt;code&gt;http://127.0.0.1:8080/v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Chat and list. Start &lt;code&gt;llama-server&lt;/code&gt; yourself.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Suggested Ollama pulls in the UI include Llama 3.2, Qwen 2.5 Coder, and Gemma 3 4B. Those are starting points for an 8 GB or 16 GB machine. Any other tag in the Ollama library works the same way.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
  browser["Browser at 127.0.0.1:8000"] --&amp;gt; api["FastAPI"]
  api --&amp;gt; db["SQLite and uploads in ./data"]
  api --&amp;gt; v1["OpenAI-compatible /v1"]
  v1 --&amp;gt; ollama["Ollama :11434"]
  v1 --&amp;gt; lm["LM Studio :1234"]
  v1 --&amp;gt; llama["llama-server :8080"]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The API is Python 3.11, FastAPI, and uvicorn. Chat, images, and benchmark rows go into SQLite under &lt;code&gt;./data&lt;/code&gt;. The UI is React and Vite, built once and served by the same process. &lt;code&gt;python -m studio --dev&lt;/code&gt; runs the API and Vite together while the interface is changing.&lt;/p&gt;

&lt;p&gt;Ollama gets a second, native client on the same port. Its OpenAI routes hide pull progress, delete, and the vision capability flag, so those calls use Ollama's own HTTP API. For every other server, vision comes from a known family name, a one-shot vision probe, or an override you set.&lt;/p&gt;

&lt;p&gt;Benchmarks are a fixed suite, version 2, with three profiles: a general mix, code generation, and one image-generation prompt. Generated code is shown as text and never executed. Image URLs are never fetched. Repeats are 1 or 3. Reports show median response time and effective throughput: output tokens divided by the full request duration, including the wait for the first token.&lt;/p&gt;

&lt;p&gt;Two write-ups shaped those choices. &lt;a href="https://dev.to/theoslater"&gt;Theo Slater&lt;/a&gt; built a desktop chat app that talks only to Ollama, and wrote that an OpenAI-compatible API should have been there from the first day: &lt;a href="https://dev.to/theoslater/i-built-a-desktop-chat-app-for-running-local-llms-offline-6im"&gt;I Built a Desktop Chat App for Running Local LLMs Offline&lt;/a&gt;. Studio starts from that API, so LM Studio and llama.cpp are a URL change. &lt;a href="https://dev.to/samhartley_dev"&gt;Sam Hartley&lt;/a&gt; is blunt that local models still lose on long reasoning, stale knowledge, and finicky vision: &lt;a href="https://dev.to/samhartley_dev/i-replaced-all-my-cloud-ai-with-local-models-heres-what-actually-broke-51k8"&gt;I Replaced All My Cloud AI With Local Models — Here's What Actually Broke&lt;/a&gt;. The benchmark page exists so that failure shows up on your own hardware.&lt;/p&gt;

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

&lt;p&gt;A closed chat API can answer the prompt. It cannot be the thing this project is for.&lt;/p&gt;

&lt;p&gt;The weights are open, so Llama, Qwen, and Gemma can be swapped with no new vendor SDK and no per-token bill. The servers are open, so the same client reaches three runtimes. Inference stays on the machine, so a transcript about a half-finished idea stays in &lt;code&gt;./data&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A hosted API would also make the speed number meaningless. &lt;a href="https://dev.to/lowspecai/tokens-per-second-is-a-memory-bandwidth-number-measure-it-in-2-seconds-1omf"&gt;Tokens per second is a memory bandwidth number&lt;/a&gt;, as &lt;a href="https://dev.to/lowspecai"&gt;@lowspecai&lt;/a&gt; put it: each token reads the weights, so the ceiling is how fast your RAM or VRAM can be read. A leaderboard from someone else's GPU does not say whether &lt;code&gt;llama3.2:3b&lt;/code&gt; is pleasant on this laptop. The same prompt, run locally with the warmup thrown away, does.&lt;/p&gt;

&lt;p&gt;Open weights are also why the lazy version can be picky. If a 3B model rambles, or a vision model calls a screenshot a flowchart, delete it and pull another one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lazy Payoff
&lt;/h2&gt;

&lt;p&gt;The model does not do the job. It removes the errand around the model.&lt;/p&gt;

&lt;p&gt;Before Studio, trying one local model meant remembering the port, remembering whether this runtime wants &lt;code&gt;ollama run&lt;/code&gt; or a loaded model in a Developer tab, pasting the prompt, then doing it again for the next model because nothing kept the transcript. Checking vision meant attaching an image and reading a confused paragraph. Checking speed meant watching the terminal and guessing.&lt;/p&gt;

&lt;p&gt;With Studio, that errand is one saved URL. The transcript is still there after refresh. The attach button is absent when the model cannot see. One benchmark row replaces the guess. The page labels that number as speed for this server and tokenizer. Whether the answer is any good is still yours to read.&lt;/p&gt;

&lt;p&gt;I do not have a stopwatch figure, and I am not going to invent one. If you timed a real run this week, put that row here. If you did not, delete this section before publishing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks
&lt;/h2&gt;

&lt;p&gt;Thanks for the challenge, and for a theme that fits a tool whose whole job is to sit on loopback and wait.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>Two products in one Hacktoberfest: a retro TV Experience and a CV that won’t invent your past</title>
      <dc:creator>Tushar Vaghela</dc:creator>
      <pubDate>Tue, 13 Oct 2026 09:38:22 +0000</pubDate>
      <link>https://dev.to/tusharv/two-products-in-one-hacktoberfest-a-retro-tv-experience-and-a-cv-that-wont-invent-your-past-2d1h</link>
      <guid>https://dev.to/tusharv/two-products-in-one-hacktoberfest-a-retro-tv-experience-and-a-cv-that-wont-invent-your-past-2d1h</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/mlh-hackathon"&gt;MLH x DEV Writing Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hacktoberfest this year asked me to ship, not just to open pull requests. I ended up with two live products that sit on opposite ends of the same idea: &lt;strong&gt;software that respects the person in front of it&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.1988.in/" rel="noopener noreferrer"&gt;1988.in&lt;/a&gt; is a television. It does not ask what to watch next.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://jobready.tech/" rel="noopener noreferrer"&gt;Job Ready&lt;/a&gt; is a CV tool. It does not invent experience you never had.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One is for my kids on the sofa. The other is for someone staring at a job post at midnight. Both came out of MLH / DEV challenge windows in October, with Cursor as the coding partner and real partner platforms underneath.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  1988.in — Feel era of 1988. No skip.
&lt;/h3&gt;

&lt;p&gt;Streaming apps train a thumb to leave. A clip has a few seconds before you decide it owes you a different clip. I missed the other feeling: a set that is already on, mid-programme, with nothing under the glass except the picture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.1988.in/" rel="noopener noreferrer"&gt;1988.in&lt;/a&gt; is that set. You accept a short station notice, press the glass, and land in the middle of whatever is on air. Bollywood is on 001. Cricket is on 002. Jungle Book, Shaktimaan, Ramayan, and the other Doordarshan-era shows live under DD Era, next to nature, food, sport, and quieter channels you can leave running. Nobody picks “what to watch next.” The channel is simply on.&lt;/p&gt;

&lt;p&gt;The piece that makes it feel like a broadcast is a clock. The same channel, the same catalog, and the same UTC second always resolve to the same video and the same start time. Two people who turn the set on in different rooms are watching the same programme, already underway. A phone can be the remote over a WebSocket: the picture stays on the computer; the phone only sends the button press.&lt;/p&gt;

&lt;p&gt;I built it for my kids. When I handed it over, they said: “Interesting.” That was enough.&lt;/p&gt;

&lt;h3&gt;
  
  
  Job Ready — show why you fit, one role at a time
&lt;/h3&gt;

&lt;p&gt;Most AI résumé tools have the same failure mode: they rewrite until the CV sounds ready, including experience you never did. That problem shows up again and again on DEV — from &lt;a href="https://dev.to/miracle_green_4ffe14e2e9b/use-ai-to-edit-your-resume-not-invent-your-experience-4imc"&gt;grounded resume editing&lt;/a&gt; to &lt;a href="https://dev.to/cornelcroi/evaluating-llm-output-in-production-validate-repair-scrub-26fd"&gt;pipelines that validate and scrub LLM output&lt;/a&gt;. I wanted the opposite product.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jobready.tech/" rel="noopener noreferrer"&gt;Job Ready&lt;/a&gt; checks one existing CV against one job. Upload a text PDF or DOCX, paste a role, and get exactly one of two results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ready to send:&lt;/strong&gt; a fact-checked rewrite, a fit report, and a downloadable PDF.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gaps to close:&lt;/strong&gt; a practice plan for required skills the work history does not show yet. No rewritten CV. No PDF. No advice to list a skill you have not done.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gemma (via Ollama) extracts structure, quotes evidence, and rewrites wording. &lt;strong&gt;Python decides suitability.&lt;/strong&gt; A skill only counts when a work bullet quote matches the saved text, or when the skills list contains the phrase. Employers, titles, dates, degrees, tools, and numbers cannot change. Failed fact checks are not saved.&lt;/p&gt;

&lt;p&gt;A missing skill on a CV is not always missing experience. Sometimes the work was real and the bullet was thin. From a flagged gap you can open a private “Update my CV” chat, explain what you actually did, review Gemma’s proposal, confirm accuracy, and reassess. The model proposes; the person confirms; code re-scores.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Television
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;a href="https://www.1988.in/" rel="noopener noreferrer"&gt;https://www.1988.in/&lt;/a&gt;, choose &lt;strong&gt;Watch TV&lt;/strong&gt;, and turn the set on. You should arrive mid-programme, with YouTube’s controls gone.&lt;/li&gt;
&lt;li&gt;Press &lt;strong&gt;CH +&lt;/strong&gt;. Snow, then a different station, also already in progress.&lt;/li&gt;
&lt;li&gt;Open &lt;strong&gt;Channels&lt;/strong&gt;, search “Ramayan” or filter by &lt;strong&gt;DD Era&lt;/strong&gt;, and tune in.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Connect remote&lt;/strong&gt;, scan the QR from a phone, and change the channel. The desktop moves. The phone never shows the video.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Source: &lt;a href="https://github.com/tusharv/positive-player" rel="noopener noreferrer"&gt;github.com/tusharv/positive-player&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Earlier write-ups: &lt;a href="https://dev.to/tusharv/feel-1988-no-skip-1i54"&gt;Feel 1988. No skip.&lt;/a&gt; · &lt;a href="https://dev.to/tusharv/a-television-with-no-skip-button-4e1k"&gt;A television with no skip button&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Job Ready
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;a href="https://jobready.tech/" rel="noopener noreferrer"&gt;https://jobready.tech/&lt;/a&gt;, create an account, and upload a text-based PDF or DOCX.&lt;/li&gt;
&lt;li&gt;Paste a role title and job description.&lt;/li&gt;
&lt;li&gt;Read the result: &lt;strong&gt;Ready to send&lt;/strong&gt; or &lt;strong&gt;Gaps to close&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If a preferred skill is missing (for example pytest), try &lt;strong&gt;Have this experience? Update your CV.&lt;/strong&gt; Write what you actually did, review the proposal, confirm, then &lt;strong&gt;Apply &amp;amp; reassess&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Source: &lt;a href="https://github.com/tusharv/green-grass" rel="noopener noreferrer"&gt;github.com/tusharv/green-grass&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Challenge write-up: &lt;a href="https://dev.to/tusharv/job-ready-tailor-your-cv-without-inventing-your-experience-32jg"&gt;Job Ready: Tailor Your CV Without Inventing Your Experience&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Partner Technologies
&lt;/h2&gt;

&lt;h3&gt;
  
  
  For 1988.in — YouTube Data API and Vercel
&lt;/h3&gt;

&lt;p&gt;Playback is the YouTube IFrame Player. Video bytes never touch my server. The expensive problem was the guide.&lt;/p&gt;

&lt;p&gt;YouTube’s daily search quota is tiny. A hundred-channel lineup driven by &lt;code&gt;search.list&lt;/code&gt; would die in one flip-through. I moved every station to a curated JSON catalog of video ids. A generator script refreshes metadata when I ask it to — never as part of &lt;code&gt;npm run build&lt;/code&gt;. Playback works with no API key; when a key is present, it only re-checks that bundled ids are still embeddable.&lt;/p&gt;

&lt;p&gt;The television itself is a static Vue 3 / Vite / Pinia app on &lt;strong&gt;Vercel&lt;/strong&gt;. The phone remote needs a public WebSocket, so &lt;code&gt;vercel.json&lt;/code&gt; rewrites &lt;code&gt;/remote-ws&lt;/code&gt; to a Function that holds an in-memory pairing hub. The desktop is authoritative. The phone sends &lt;code&gt;channelStep&lt;/code&gt;, &lt;code&gt;volumeStep&lt;/code&gt;, mute, and power. Sessions live in that process; video never passes through it. Locally the same hub runs in Node with a Vite proxy.&lt;/p&gt;

&lt;p&gt;That split taught me something I keep repeating: the product is the clock and the remote protocol, not a programme database.&lt;/p&gt;

&lt;h3&gt;
  
  
  For Job Ready — Gemma, Render, and a .tech domain
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Gemma&lt;/strong&gt; (&lt;code&gt;gemma4:31b&lt;/code&gt; through Ollama) runs the language work: CV extraction, job-skill extraction, evidence quotes, rewrites, gap plans, and clarification edits. Suitability stays in &lt;code&gt;fit.py&lt;/code&gt;. Fact checks stay in &lt;code&gt;facts.py&lt;/code&gt;. Chat proposals stay grounded in the person’s exact messages in &lt;code&gt;cv_chat.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Render&lt;/strong&gt; hosts the FastAPI + Svelte 5 app and PostgreSQL. A Blueprint in &lt;code&gt;render.yaml&lt;/code&gt; wires the web service, database, health check, and env so a redeploy is a checkout plus an Ollama key — not a day of clicking console forms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;jobready.tech&lt;/strong&gt; is the public address. The name matches the promise: one role, an honest next step, not a match-percentage theatre.&lt;/p&gt;

&lt;p&gt;Open weights matter here because CV extraction, evidence screening, and conversational edits fail in different ways. I can swap or tune the model while keeping scoring and confirmation as application rules — the same instinct as production LLM validation posts on DEV, applied to someone’s career story.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hackathon Experience
&lt;/h2&gt;

&lt;p&gt;October was a stack of MLH surfaces, not one weekend in a gymnasium.&lt;/p&gt;

&lt;p&gt;I checked in at &lt;strong&gt;Hacktoberfest Hack Day Mumbai x FAIR&lt;/strong&gt;, stayed registered for &lt;strong&gt;Hacktoberfest 2026&lt;/strong&gt; and &lt;strong&gt;Global Hack Week: Hacktoberfest&lt;/strong&gt;, and shipped into the DEV challenge windows: the &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01"&gt;Weekend Challenge&lt;/a&gt; for 1988.in, then &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Week 2: Side Hustle&lt;/a&gt; for Job Ready.&lt;/p&gt;

&lt;p&gt;What I will remember most is the contrast in the room and on the screen. At the Hack Day the energy was familiar MLH: people pairing, demos half-working, someone hunting a cable. Online, the challenges forced a sharper question each Monday — build for a friend, then build something someone might pay for. 1988.in answered the first with a set for my kids. Job Ready answered the second with a product I would actually trust with my own CV.&lt;/p&gt;

&lt;p&gt;The technical moments that stuck:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two browsers on 1988.in, same channel, same second of the same video, with no server choosing the schedule. That was the first time it felt like television.&lt;/li&gt;
&lt;li&gt;A Job Ready assessment that refused a “ready” PDF because a quote did not match the source bullet. Annoying in the moment. Correct for the product.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are in an MLH week right now: ship the weird small thing and the serious useful thing. Write both up. The weekend ends; the story is how other builders learn what you learned the hard way.&lt;/p&gt;

</description>
      <category>mlhacks</category>
      <category>devchallenge</category>
      <category>hackathon</category>
      <category>ai</category>
    </item>
    <item>
      <title>Job Ready: Tailor Your CV Without Inventing Your Experience</title>
      <dc:creator>Tushar Vaghela</dc:creator>
      <pubDate>Tue, 13 Oct 2026 06:39:54 +0000</pubDate>
      <link>https://dev.to/tusharv/job-ready-tailor-your-cv-without-inventing-your-experience-32jg</link>
      <guid>https://dev.to/tusharv/job-ready-tailor-your-cv-without-inventing-your-experience-32jg</guid>
      <description>&lt;h1&gt;
  
  
  Job Ready: An Honest Next Step for Your Next Role
&lt;/h1&gt;

&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;I built &lt;strong&gt;Job Ready&lt;/strong&gt;, an app that checks your existing CV against a specific job and helps you take the next step without inventing experience.&lt;/p&gt;

&lt;p&gt;Upload a PDF or DOCX, paste the role title and job description, and get one of two results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ready to send:&lt;/strong&gt; a fact-checked CV rewrite, a fit report, and a downloadable PDF.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gaps to close:&lt;/strong&gt; a practice plan, with missing required skills listed before missing preferred skills.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But a missing skill on a CV does not always mean missing experience. Sometimes you have done the work and simply left it out.&lt;/p&gt;

&lt;p&gt;Job Ready addresses that through a private &lt;strong&gt;“Update my CV”&lt;/strong&gt; conversation. From a flagged major or minor gap, you can explain what you actually did. Gemma proposes changes supported by your statements, you review and confirm their accuracy, and the application updates your CV and reassesses that role.&lt;/p&gt;

&lt;p&gt;That creates a useful loop: assess the CV, surface missing evidence, clarify real experience, and check again. If you still have a gap, the practice plan gives you something concrete to work on.&lt;/p&gt;

&lt;p&gt;The intended customers are job seekers preparing several applications and career coaches helping clients describe their experience clearly. My business hypothesis is that they would pay for less repetitive editing, evidence-backed CV updates, and focused preparation for each role. Paying-customer demand still needs validation.&lt;/p&gt;

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

&lt;p&gt;Try &lt;strong&gt;&lt;a href="https://jobready.tech" rel="noopener noreferrer"&gt;Job Ready&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Create an account, upload a text-based PDF or DOCX CV, and paste a job description.&lt;/p&gt;

&lt;p&gt;Here is one example of the clarification flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The assessment flags &lt;strong&gt;pytest&lt;/strong&gt; as a missing preferred skill—a &lt;strong&gt;minor gap&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The person selects &lt;strong&gt;“Have this experience? Update your CV.”&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;In the private conversation, they write: &lt;strong&gt;“I have worked with pytest.”&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Gemma proposes adding pytest to the skills list by asking some questions.&lt;/li&gt;
&lt;li&gt;The person reviews the proposed edit and confirms that it accurately describes their experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;“Apply &amp;amp; reassess”&lt;/strong&gt; saves the change and runs the role check again.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The same flow is available for missing required skills, which are marked as major gaps. An update does not automatically make someone ready: the application calculates the result again using its existing rules.&lt;/p&gt;

&lt;p&gt;The person can also choose to refresh their shared profile. Other saved role checks retain their previous assessments.&lt;/p&gt;

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

&lt;p&gt;The code is available on GitHub:&lt;/p&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/tusharv" rel="noopener noreferrer"&gt;
        tusharv
      &lt;/a&gt; / &lt;a href="https://github.com/tusharv/green-grass" rel="noopener noreferrer"&gt;
        green-grass
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Your next role. An honest next step.
    &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;Job Ready&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Job Ready, at &lt;a href="https://jobready.tech" rel="nofollow noopener noreferrer"&gt;jobready.tech&lt;/a&gt;, checks one CV against one job. A signed-in person uploads a text PDF or DOCX, pastes a role, and gets one of two honest results: a fact-checked CV they can download as a PDF, or a practice plan for required skills the work history does not show.&lt;/p&gt;
&lt;p&gt;The model extracts structure and rewrites wording. It does not decide whether the CV is ready, and it does not invent employers, titles, dates, degrees, tools, or numbers. Suitability is scored in code.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What you get&lt;/h2&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Upload a text PDF or DOCX. The original file is discarded. The server keeps the extracted text and a structured profile.&lt;/li&gt;
&lt;li&gt;Paste a role title and job description.&lt;/li&gt;
&lt;li&gt;The server pulls required and preferred skills from the posting, then scores the saved profile.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ready to send&lt;/strong&gt; when the score clears the bar: a rewritten CV, the fit report, and a…&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/tusharv/green-grass" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The main pieces are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;app/services/pipeline.py&lt;/code&gt; — coordinates extraction, assessment, and the resulting CV or gap plan.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app/services/fit.py&lt;/code&gt; — validates supporting quotes and calculates suitability.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app/services/facts.py&lt;/code&gt; — checks generated CVs and gap plans before saving.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app/services/cv_chat.py&lt;/code&gt; — restricts proposed CV edits and grounds them in the person’s statements.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app/cv_chat_routes.py&lt;/code&gt; — manages private conversations, confirmation, and applying updates.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Job Ready uses &lt;strong&gt;Gemma through Ollama&lt;/strong&gt;, with &lt;code&gt;gemma4:31b&lt;/code&gt; as the configured default model.&lt;/p&gt;

&lt;p&gt;Gemma handles the language tasks throughout the workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extracting a structured profile from CV text.&lt;/li&gt;
&lt;li&gt;Extracting required and preferred skills from a job posting.&lt;/li&gt;
&lt;li&gt;Identifying work-history quotes that support a skill.&lt;/li&gt;
&lt;li&gt;Rewriting existing experience for the target role.&lt;/li&gt;
&lt;li&gt;Creating practice plans for missing skills.&lt;/li&gt;
&lt;li&gt;Turning user-provided clarification into proposed CV edits.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Keeping assessment grounded
&lt;/h3&gt;

&lt;p&gt;The suitability decision belongs to Python code.&lt;/p&gt;

&lt;p&gt;The application combines required-skill coverage and years of experience using a fixed formula. Work-history quotes must match the saved source text. Skills-list matches are checked in code, and preferred skills do not block suitability.&lt;/p&gt;

&lt;p&gt;Gemma helps interpret and express information, while the application controls which evidence is accepted and which result is available.&lt;/p&gt;

&lt;p&gt;Generated CVs also pass through fact checks. Protected facts such as employers, titles, and dates must remain intact. Contact details and education come from the saved profile. Failed checks are not saved.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clarifying experience before changing the CV
&lt;/h3&gt;

&lt;p&gt;The private chat handles an important distinction: &lt;strong&gt;“not evidenced in your CV” can mean either missing experience or missing information.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Gemma proposes edits from the conversation, and server-side checks require supporting text from the person’s messages. Added skills must be explicitly supported. Work-history changes require the employer to be named, and new numbers need source support.&lt;/p&gt;

&lt;p&gt;For example, “I have worked with pytest” can support adding pytest to the skills list. It does not establish which employer used it, how long the person used it, or what measurable results they achieved.&lt;/p&gt;

&lt;p&gt;Proposals remain unsaved until the person reviews them, confirms their accuracy, and selects &lt;strong&gt;“Apply &amp;amp; reassess.”&lt;/strong&gt; Applying a proposal updates the source CV and current assessment together, with an optional update to the shared profile.&lt;/p&gt;

&lt;p&gt;The chat can edit the summary, skills, and existing work bullets. It cannot change identity fields, education, or total years of experience. The original extracted upload text remains unchanged.&lt;/p&gt;

&lt;p&gt;These checks validate that a proposed edit is supported by the person’s statements. They do not independently verify that the experience happened.&lt;/p&gt;

&lt;h3&gt;
  
  
  The application stack
&lt;/h3&gt;

&lt;p&gt;The interface uses &lt;strong&gt;Svelte 5&lt;/strong&gt;, with &lt;strong&gt;FastAPI and Pydantic&lt;/strong&gt; handling the backend and structured data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;pypdf&lt;/strong&gt; and &lt;strong&gt;python-docx&lt;/strong&gt; extract CV text. &lt;strong&gt;WeasyPrint&lt;/strong&gt; generates PDFs for ready results. The original uploaded file is discarded after extraction; extracted text and a structured profile are retained.&lt;/p&gt;

&lt;p&gt;The app uses &lt;strong&gt;SQLite locally&lt;/strong&gt; and &lt;strong&gt;PostgreSQL on Render&lt;/strong&gt;. FastAPI serves the built frontend, keeping deployment within one application.&lt;/p&gt;

&lt;p&gt;Automated API tests use scripted model responses so the application’s rules can be checked without calling a live model.&lt;/p&gt;

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

&lt;p&gt;For Job Ready, open innovation means having room to improve the model behind a very specific workflow.&lt;/p&gt;

&lt;p&gt;CV extraction, evidence screening, and conversational edits have different failure modes. A model might rewrite a sentence well but infer too much from a short statement about someone’s experience. Open weights create the opportunity to evaluate alternative models and explore targeted tuning for those tasks.&lt;/p&gt;

&lt;p&gt;The model and host are configurable, while scoring, evidence checks, and confirmation remain application rules. That separation gives me a way to evolve the AI component while keeping the product’s constraints explicit.&lt;/p&gt;

&lt;p&gt;The current configuration uses Ollama’s hosted service. I am not claiming that CV processing happens entirely on the user’s machine. Running inference on infrastructure I control is a future option that open weights make possible.&lt;/p&gt;

&lt;p&gt;A closed API could implement this workflow too. The additional value of open weights is the ability to work directly with the model, explore self-hosting, and investigate improvements beyond a provider’s hosted interface.&lt;/p&gt;

&lt;p&gt;For a potential paid service handling personal career information, that flexibility matters: it gives me more choices about deployment, operating costs, and how the system develops.&lt;/p&gt;

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

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

&lt;p&gt;Gemma is central to the complete application journey: extracting the CV, understanding job requirements, finding supporting evidence, rewriting grounded content, and producing practice plans.&lt;/p&gt;

&lt;p&gt;It also powers the private clarification flow for &lt;strong&gt;both major and minor gaps&lt;/strong&gt;. When someone has relevant experience that their CV omitted, Gemma turns their explanation into proposed edits. Server-side checks ground those edits in their exact statements, and explicit user confirmation is required before anything is applied.&lt;/p&gt;

&lt;p&gt;The pytest example shows this in practice: a missing preferred skill becomes a proposed skills-list addition supported by the person’s own words. The application then reassesses the role using its deterministic scoring rules.&lt;/p&gt;

&lt;p&gt;This combines Gemma’s language capabilities with evidence checks and human review at the point where personal claims change.&lt;/p&gt;

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

&lt;p&gt;Render hosts Job Ready’s FastAPI backend, Svelte interface, and PostgreSQL database.&lt;/p&gt;

&lt;p&gt;I also added a &lt;strong&gt;Render Blueprint&lt;/strong&gt; in &lt;code&gt;render.yaml&lt;/code&gt; to make deployment straightforward. It defines the web service, database connection, health check, and environment configuration, so someone deploying the project does not have to configure each resource manually.&lt;/p&gt;

&lt;p&gt;With the repository and an Ollama API key ready, setup takes around &lt;strong&gt;five minutes&lt;/strong&gt;, plus build and provisioning time.&lt;/p&gt;

&lt;p&gt;The deployed backend handles CV processing, Gemma requests, private clarification conversations, saved assessments, and eligible PDF downloads.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://dev.to/challenges/hf26#best-use-of-a-tech-domain"&gt;Best Use of a .tech Domain&lt;/a&gt; 🆕
&lt;/h3&gt;

&lt;p&gt;Job Ready is live at &lt;strong&gt;&lt;a href="https://jobready.tech" rel="noopener noreferrer"&gt;jobready.tech&lt;/a&gt;&lt;/strong&gt;, giving the project a clear, memorable address that matches its purpose: helping people prepare for their next role.&lt;/p&gt;

&lt;p&gt;The domain brings the complete experience together—from uploading a CV and checking a role to clarifying experience with Gemma and sharing a profile with employers.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>A television with no skip button</title>
      <dc:creator>Tushar Vaghela</dc:creator>
      <pubDate>Wed, 07 Oct 2026 19:18:06 +0000</pubDate>
      <link>https://dev.to/tusharv/a-television-with-no-skip-button-4e1k</link>
      <guid>https://dev.to/tusharv/a-television-with-no-skip-button-4e1k</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/mlh-hackathon"&gt;MLH x DEV Writing Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Reels trained my thumb to leave. A clip has a few seconds before I decide it owes me a different clip. I missed the other feeling: a television that is already on, in the middle of something, with nothing under the glass except the picture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://1988.in/" rel="noopener noreferrer"&gt;1988.in&lt;/a&gt; is that set. You press the glass to turn it on and land in the middle of whatever is on air. There is no progress bar and no next clip waiting. If you want a different picture, you change the channel.&lt;/p&gt;

&lt;p&gt;The lineup opens the way an evening in India used to. Channel 001 is Bollywood. Then cricket, Jungle Book, Shaktimaan, a month of DD Classics, Ramayan, and Mahabharat. After those come animals, street food, space, sport, and travel, and then the quieter stations: rain, a hearth, a forest, a lake. Channel 013, Vintage India, is a curated run of old advertisements, public-service films, and broadcast interludes — 198 videos, kept short on purpose, about two hours and fifty minutes from start to finish. The full set is 125 channels. Each one ships as its own list of YouTube video ids, titles, and durations.&lt;/p&gt;

&lt;p&gt;1988 is the year on the glass. The programmes come from many years, and every one of them plays through YouTube. The app never downloads, rehosts, or proxies the video.&lt;/p&gt;

&lt;p&gt;The piece that makes it feel like a broadcast is a clock. The same channel, the same catalog, and the same UTC second always resolve to the same video and the same start time. Two people who turn the set on in different rooms are watching the same programme, already underway. A catalog shorter than a day rotates its opening programme by the UTC date, so Tuesday is a different timetable from Monday. A catalog longer than a day plays straight through midnight. When a video ends, the clock chooses the next slot. YouTube's up-next row never gets a vote.&lt;/p&gt;

&lt;p&gt;The YouTube player is real, and its controls are hidden. Scanlines, grain, and a vignette are a CSS layer on top of the iframe. A CSS filter on the iframe itself fights the player, so the glass treatment stays on a separate layer and ignores pointer events. Changing channel runs a short analog zap: snow, a horizontal tear, and the new picture already loading underneath. &lt;code&gt;prefers-reduced-motion&lt;/code&gt; keeps still scanlines and replaces the zap with a brief dark frame. Volume lives on the glass, in steps of five. The channel and volume HUD fades after a few seconds of quiet. The first tap, arrow, or OK press only wakes it.&lt;/p&gt;

&lt;p&gt;A phone can be the remote. The computer shows a QR code and an eight-character code. The phone joins over a WebSocket and can send power, channel, volume, and mute. The desktop answers with its real state, including changes made on the glass. Picture and sound stay on the computer. One phone pairs with each set. An invite lasts five minutes and is used up on the first join. A disconnected desktop has two minutes to return. A session lasts twelve hours. Presses made while the phone is offline are dropped. A remote that replays a stale command after it reconnects is a worse remote than one that missed a press.&lt;/p&gt;

&lt;p&gt;The app is Vue 3, Vite, Pinia, and Vue Router. One Pinia store owns power, channel, volume, interruption, and the current slot. Components draw the set. They do not call YouTube.&lt;/p&gt;

&lt;p&gt;A shared clock is the product. Computing &lt;code&gt;{ videoId, startSeconds }&lt;/code&gt; from UTC is what makes two browsers agree. A random pick per session would be a website with a bezel.&lt;/p&gt;

&lt;p&gt;Search quota ends a demo. YouTube's Data API allows very few &lt;code&gt;search.list&lt;/code&gt; calls per day. &lt;code&gt;videos.list&lt;/code&gt; is cheap by comparison. Viewers no longer search. Each channel is a JSON file, lazy-loaded only when that station is tuned. The home page, the guide, and the phone never download those lists. Playback works with no API key. When a key is present, it only re-checks that the bundled ids are still embeddable and still have a duration.&lt;/p&gt;

&lt;p&gt;Embeddable is a moment, not a promise. Public playlists contain private, deleted, regional, and non-embeddable videos. A catalog that played on Saturday can fail on Sunday. That channel shows an interruption card and retries. Another station is never quietly substituted. If Cricket cannot play, the set does not put on Nature and hope you will not notice.&lt;/p&gt;

&lt;p&gt;The power button is the browser gesture and the legal gate. Sound will not start without a click. That same click is where the viewer agrees to the privacy policy, the terms, and YouTube's terms. The Data API and the iframe stay idle until then.&lt;/p&gt;

&lt;p&gt;Nostalgia needs a boundary. I wanted the feeling of that era of Indian television. I did not put an official broadcaster mark on the glass. The site says so in the footer.&lt;/p&gt;

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

&lt;p&gt;The set is live at &lt;a href="https://1988.in/" rel="noopener noreferrer"&gt;https://1988.in/&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choose &lt;strong&gt;Watch TV&lt;/strong&gt; and turn the set on. You should arrive in the middle of a programme, with the YouTube controls gone.&lt;/li&gt;
&lt;li&gt;Press &lt;strong&gt;CH +&lt;/strong&gt; or the right arrow. Snow, then a different station, also already in progress.&lt;/li&gt;
&lt;li&gt;Open &lt;strong&gt;Channels&lt;/strong&gt;. Search "cricket", or filter by the &lt;strong&gt;DD Era&lt;/strong&gt; tag, and tune in.&lt;/li&gt;
&lt;li&gt;On the computer, choose &lt;strong&gt;Connect remote&lt;/strong&gt;. Scan the QR code, or open &lt;code&gt;/remote&lt;/code&gt; and type the eight-character code. Change the channel from the phone. The desktop moves. The phone never shows the video.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Source: &lt;a href="https://github.com/tusharv/positive-player" rel="noopener noreferrer"&gt;github.com/tusharv/positive-player&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Partner Technologies
&lt;/h2&gt;

&lt;p&gt;The two platforms this project actually depends on, beyond the Vue app, are the YouTube Data API through Google Cloud, and Vercel.&lt;/p&gt;

&lt;h3&gt;
  
  
  YouTube Data API on Google Cloud
&lt;/h3&gt;

&lt;p&gt;Playback is the IFrame Player API. That part spends no Data API quota. Catalogs are the expensive problem.&lt;/p&gt;

&lt;p&gt;The first lineup was search queries, one per channel. Flipping through the set could burn the daily Search Queries budget, which is a separate, much smaller bucket than the general 10,000-unit pool. I moved every station to a curated bundle. A generator script runs only when I ask it to, never as part of &lt;code&gt;npm run build&lt;/code&gt;. It checks metadata, keeps up to 50 videos for a generated channel, preserves hand-picked selections, and refuses to replace the files if any generated channel would be left with fewer than three videos. A changed bundle gets a new cache key, so a viewer's browser does not keep yesterday's list under today's name.&lt;/p&gt;

&lt;p&gt;Two stations are hand-kept. Channel 005, DD Classics, is a 34-day rotation of serials, comedy, culture, and vintage ads. Channel 013, Vintage India, keeps the short ad spots that a "drop anything under 60 seconds" rule would have thrown away. Curated items shorter than one second are still dropped. Ordinary catalogs still drop anything under a minute.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vercel
&lt;/h3&gt;

&lt;p&gt;The television is a static build. The remote needs a public WebSocket, and a static host does not provide one.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vercel.json&lt;/code&gt; rewrites &lt;code&gt;/remote-ws&lt;/code&gt; to a Function, &lt;code&gt;api/remote-ws.mjs&lt;/code&gt;, with &lt;code&gt;maxDuration&lt;/code&gt; set to 300 seconds. The function includes the server code, the shared protocol module, and the channel data. The hub checks channel numbers against the real lineup, so a phone cannot tune to a station that does not exist.&lt;/p&gt;

&lt;p&gt;The function holds an in-memory session hub. The desktop creates a session and receives an id, a host token, the eight-character code, and an invite. The phone joins with the code or the invite and receives a remote token. From then on the phone sends commands (&lt;code&gt;channelStep&lt;/code&gt;, &lt;code&gt;volumeStep&lt;/code&gt;, &lt;code&gt;digit&lt;/code&gt;, &lt;code&gt;mute&lt;/code&gt;, &lt;code&gt;powerOff&lt;/code&gt;, &lt;code&gt;powerToggle&lt;/code&gt;) and the desktop sends state. The host is authoritative. The phone cannot write the channel except by a command the TV applies through the same store as a key on the glass. The socket's origin has to match the request host. Idle connections are swept.&lt;/p&gt;

&lt;p&gt;The ceiling is honest. Sessions live in that one process, up to 1,000 televisions, and they disappear when the process does. Two instances cannot share one paired phone and TV. For a room of sets, that is the right shape. A remote that has to survive many instances needs shared session storage and a way to deliver a command to the process that still holds the desktop socket. Video never passes through the function. The bytes go from YouTube to the browser.&lt;/p&gt;

&lt;p&gt;Locally, the same hub runs in Node and Vite proxies &lt;code&gt;/remote-ws&lt;/code&gt; to it. One protocol module, two places it can run. A self-hosted box can also serve the built site and the socket from a single Node process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hackathon Experience
&lt;/h2&gt;

&lt;p&gt;The moment from the software that I keep is a small one. Two browsers, one channel, the same second of the same video, with no server choosing the schedule. That was the first time it felt like a television.&lt;/p&gt;

</description>
      <category>mlhacks</category>
      <category>devchallenge</category>
      <category>hackathon</category>
    </item>
    <item>
      <title>Feel 1988. No skip. 📺</title>
      <dc:creator>Tushar Vaghela</dc:creator>
      <pubDate>Mon, 05 Oct 2026 04:30:00 +0000</pubDate>
      <link>https://dev.to/tusharv/feel-1988-no-skip-1i54</link>
      <guid>https://dev.to/tusharv/feel-1988-no-skip-1i54</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01"&gt;Hacktoberfest Weekend Challenge: Build for a Friend&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;I built &lt;a href="https://1988.in/" rel="noopener noreferrer"&gt;https://1988.in/&lt;/a&gt; for my kids.&lt;/p&gt;

&lt;p&gt;1988.in is a television that lives in the browser. You accept a short station notice, press the glass, and the set comes on already in the middle of a programme. Bollywood is on 001. Cricket is on 002. Jungle Book, Shaktimaan, and the other Doordarshan-era shows are in the guide under DD Era, next to nature, food, sport, and quieter channels you can leave running. Nobody picks “what to watch next.” The channel is simply on.&lt;/p&gt;

&lt;p&gt;That is the problem it solves. Streaming apps ask for an account, a search, and a decision. A television asks you to sit down. Channel, volume, and mute stay in that browser, including changes made from a paired phone. Turn the set on again and you are back on the same channel, mid-broadcast.&lt;/p&gt;

&lt;p&gt;When I handed it over, they said: “Interesting”&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://1988.in/" rel="noopener noreferrer"&gt;https://1988.in/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On a laptop, open the TV, accept the notice, and press power. Open &lt;strong&gt;Channels&lt;/strong&gt; and search “Ramayan” or the DD Era tag. On a phone on the same page, choose &lt;strong&gt;Connect remote&lt;/strong&gt;, scan the QR code, and change the channel. The picture stays on the computer. The phone only sends the button press.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://github.com/tusharv/positive-player" rel="noopener noreferrer"&gt;https://github.com/tusharv/positive-player&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The lineup is &lt;code&gt;src/data/channels.ts&lt;/code&gt;. The broadcast clock is &lt;code&gt;src/lib/broadcastClock.ts&lt;/code&gt;. The television state lives in one Pinia store, &lt;code&gt;src/stores/tv.ts&lt;/code&gt;. The phone speaks a small WebSocket protocol. Video bytes go straight to YouTube.&lt;/p&gt;

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

&lt;p&gt;The set is a Vue 3 single-page app: Vite, Pinia, Vue Router. YouTube’s IFrame Player paints the picture. YouTube Data API v3 fills the guide from each channel’s public uploads playlist. A Vercel function at &lt;code&gt;/remote-ws&lt;/code&gt; relays the phone. The same relay runs as a small Node process for local development and self-hosting.&lt;/p&gt;

&lt;p&gt;Each channel is a playlist id, not a search. A default YouTube project allows 100 search calls a day, which a hundred-channel lineup would burn in one flip-through. Playlist and video lookups sit in the ordinary quota, and a catalog younger than seven days stays in the browser.&lt;/p&gt;

&lt;p&gt;The illusion of a broadcast is a clock. Durations in the catalog are summed into a loop. The UTC second, modulo that loop, picks the video and how many seconds into it you join. Two people who turn on the same channel in the same second join the same moment. When a video ends or will not embed, that id is dropped for the rest of the tab and the clock runs again.&lt;/p&gt;

&lt;p&gt;The phone never touches YouTube. The TV shows a QR code and an eight-character pairing code. One phone pairs to one set. The desktop sends its real state back, so a channel change on the glass shows up on the phone, and a channel change on the phone shows up on the glass. Sessions live in memory, invitations expire, and a disconnect gives the desktop two minutes to return.&lt;/p&gt;

&lt;p&gt;I built it with Cursor, from a written spec through to the Samsung TV fix in 0.4.1. On those sets, YouTube draws on a separate hardware plane, so a full-screen scanline layer hides the picture while the sound keeps playing. The player detects that and turns the glass effects off. That was a coding agent helping me write a website. The running programme does not call a model.&lt;/p&gt;

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

&lt;p&gt;The part a family actually touches is open because it is a web page.&lt;/p&gt;

&lt;p&gt;There is no account on 1988.in. Power, channel, and volume stay in the browser that is sitting in the room. The remote is another browser tab. Pairing credentials stay in that tab. A closed streaming app would have put the lineup, the history, and the remote behind a login on someone else’s server. Here the lineup is a file in the repository. The schedule is arithmetic on UTC, so there is no programme database to run, pay for, or lose. Video stays on YouTube, which is the closed piece, and the television around it can be read, changed, and self-hosted.&lt;/p&gt;

&lt;p&gt;What that made possible is a set you can leave on for someone who does not want another app. They press the glass. Something is already playing. They pass the phone across the sofa.&lt;/p&gt;

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

&lt;p&gt;The design spec and the implementation notes are in the repository under &lt;code&gt;docs/superpowers/&lt;/code&gt; and &lt;code&gt;docs/architecture.md&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>hf26challenge</category>
    </item>
  </channel>
</rss>
