<?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: Senthil raja .R</title>
    <description>The latest articles on DEV Community by Senthil raja .R (@senthil_raja_r).</description>
    <link>https://dev.to/senthil_raja_r</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%2F3923680%2F6d9264de-2639-4d2b-b36d-e3389d847ce0.jpg</url>
      <title>DEV Community: Senthil raja .R</title>
      <link>https://dev.to/senthil_raja_r</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/senthil_raja_r"/>
    <language>en</language>
    <item>
      <title>Ghost in the Machine: DEADLOOP, a Local-First Reliability Monitor for AI Agents</title>
      <dc:creator>Senthil raja .R</dc:creator>
      <pubDate>Thu, 29 Oct 2026 18:28:28 +0000</pubDate>
      <link>https://dev.to/senthil_raja_r/ghost-in-the-machine-deadloop-a-local-first-reliability-monitor-for-ai-agents-3j7m</link>
      <guid>https://dev.to/senthil_raja_r/ghost-in-the-machine-deadloop-a-local-first-reliability-monitor-for-ai-agents-3j7m</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/Senthil455/DeadLoop" rel="noopener noreferrer"&gt;https://github.com/Senthil455/DeadLoop&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This Halloween I built &lt;strong&gt;DEADLOOP&lt;/strong&gt;: a reliability and safety monitor for AI agents that detects when they get trapped in repetitive tool calls, unproductive loops, or circular workflows. It records execution traces, raises evidence-backed incidents, and lets a human acknowledge, resolve, dismiss, or request a pause. The core is fully deterministic; an optional open-weight model only explains the findings. It never changes a finding or executes an intervention.&lt;/p&gt;

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

&lt;p&gt;DEADLOOP is a monitor, not an agent framework. Your agent keeps running as-is. DEADLOOP ingests its tool-call trace and answers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is this repetition, or legitimate retrying?&lt;/li&gt;
&lt;li&gt;What exactly supports that conclusion?&lt;/li&gt;
&lt;li&gt;What should a human look at first?&lt;/li&gt;
&lt;li&gt;Can we stop the run without claiming control we do not have?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Detectors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exact repetition&lt;/li&gt;
&lt;li&gt;Near-duplicate repetition&lt;/li&gt;
&lt;li&gt;A-B-A-B oscillation&lt;/li&gt;
&lt;li&gt;Repeated failure&lt;/li&gt;
&lt;li&gt;Explicit no-progress&lt;/li&gt;
&lt;li&gt;Session budgets (tool calls, duration, tokens, cost)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every incident cites real event IDs, the observed sequence, measured metrics, confidence basis, and stated uncertainty. Risk scores are heuristics in &lt;code&gt;[0, 100]&lt;/code&gt;, not probabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  The spooky part
&lt;/h2&gt;

&lt;p&gt;Every developer has watched an agent whisper the same command into the void over and over, burning tokens while nothing moves. DEADLOOP is the thing in the machine that notices the ghost repeating itself and breaks the cycle. It is not a horror game aesthetic; it is a forensic one: dark, precise, and readable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why open innovation matters for this
&lt;/h2&gt;

&lt;p&gt;The open pieces are what make the project work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It runs offline.&lt;/strong&gt; Detection, risk scoring, ingestion, and incident management are deterministic and local. No API key is required for the core product to function.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It keeps data off servers you do not control.&lt;/strong&gt; Execution traces can contain tool arguments, outputs, and errors. DEADLOOP redacts credential-shaped fields at two layers: the SDK before transport, and the backend before storage. Raw ingestion keys are never returned after creation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It is not locked inside a disappearing service.&lt;/strong&gt; The stack is FastAPI, SQLAlchemy, SQLite/PostgreSQL, React, and Vite. The detector never depends on a hosted model. If the optional AI provider is disabled, slow, or returns invalid output, the deterministic explanation remains available.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optional open-weight AI.&lt;/strong&gt; Explanations can use an OpenAI-compatible endpoint, verified with Gemma 2 2B through Ollama. No API key is required for a local endpoint. Detection remains on-device either way.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost.&lt;/strong&gt; The basic product requires no paid external services.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Where the open-based approach worked better than a closed one: a closed tracing service would show that calls happened, but it would not let me keep traces local, swap or disable the model, or explain exactly why a finding occurred. DEADLOOP can run with the internet off and still tell you what happened.&lt;/p&gt;

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

&lt;p&gt;The sample simulator generates real execution events through the same ingestion, persistence, detection, and incident paths as production. The exact-repetition scenario creates four identical failing calls and produces both exact-repetition and repeated-failure findings. Evidence references the real event IDs; you can open the incident, inspect the timeline, acknowledge it, request a pause, approve it, and verify the simulator acknowledges it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code that matters
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Send one event from any agent
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;deadloop&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DeadLoopClient&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DeadLoopClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://127.0.0.1:8000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dl_...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;agent_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;research-agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;run-42&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tool_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;search_web&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;database connection error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;progress&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Run the backend&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;backend&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;venv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;venv&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;venv&lt;/span&gt;&lt;span class="nx"&gt;\Scripts\Activate.ps1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;pip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;requirements.txt&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;alembic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;alembic.ini&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;upgrade&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;DEADLOOP_ADMIN_TOKEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"choose-a-long-random-token"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;DEADLOOP_AUTO_CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;uvicorn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;app.main:app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;127.0.0.1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;8000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Build the frontend&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;frontend&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;npm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ci&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;npm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&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; and sign in with the configured admin token.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verification
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Backend pytest: 62 passed, 0 failed&lt;/li&gt;
&lt;li&gt;SDK pytest: 8 passed, 0 failed&lt;/li&gt;
&lt;li&gt;Frontend Vitest: 8 passed, 0 failed&lt;/li&gt;
&lt;li&gt;Frontend production build: passed&lt;/li&gt;
&lt;li&gt;Clean-database Alembic migration: passed, 11 tables&lt;/li&gt;
&lt;li&gt;Live API acceptance workflow: passed with 0 failures&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Security notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Secrets are not hardcoded; they come from environment variables.&lt;/li&gt;
&lt;li&gt;Inputs and configuration values are validated.&lt;/li&gt;
&lt;li&gt;Protected endpoints enforce authorization on the backend.&lt;/li&gt;
&lt;li&gt;Intervention operations require approval and are audited.&lt;/li&gt;
&lt;li&gt;External AI data transfer requires explicit configuration.&lt;/li&gt;
&lt;li&gt;Known limitations are documented, including single-node scope, no multi-tenant RBAC, and no built-in TLS.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>GhostShift AI: The Local Automation Studio That Does the Chores You Keep Putting Off</title>
      <dc:creator>Senthil raja .R</dc:creator>
      <pubDate>Sun, 25 Oct 2026 14:51:17 +0000</pubDate>
      <link>https://dev.to/senthil_raja_r/ghostshift-ai-the-local-automation-studio-that-does-the-chores-you-keep-putting-off-2k83</link>
      <guid>https://dev.to/senthil_raja_r/ghostshift-ai-the-local-automation-studio-that-does-the-chores-you-keep-putting-off-2k83</guid>
      <description>&lt;h2&gt;
  
  
  The lazy payoff
&lt;/h2&gt;

&lt;p&gt;We all have that folder. The Downloads folder. The &lt;code&gt;Documents&lt;/code&gt; dumping ground. The logs directory that's grown to ten thousand lines. You know you should tidy it, sort it, review it — but it's boring, it's repetitive, and it always feels like it can wait until tomorrow.&lt;/p&gt;

&lt;p&gt;GhostShift AI is built for exactly that procrastination. It's a local-first automation studio that scans, classifies, analyzes, and archives the files and logs already on your machine — but only after you approve each step. It does the work so you don't have to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GhostSort&lt;/strong&gt; watches a folder you register, proposes where each file should go, shows you a preview, and moves only what you explicitly approve. Fingerprint-verified undo means if you change your mind, it goes back exactly where it came from.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GhostDev&lt;/strong&gt; reads your log files, groups errors deterministically, and (if you have a local model) adds a clearly labelled interpretation — without sending your logs anywhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GhostCapture&lt;/strong&gt; records an allowlisted sequence of file actions (no screen recording, no browser snooping), lets you edit and reorder the steps, then replays them as a dry run or live run whenever you want.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GhostBrain&lt;/strong&gt; drafts new workflows from a plain-language prompt using a local open-weight model — and nothing executes until you say so.&lt;/p&gt;

&lt;p&gt;It's slow and steady by design: AI suggests, deterministic code validates, you authorize, the engine executes, history records.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why open innovation matters here
&lt;/h2&gt;

&lt;p&gt;GhostShift runs entirely on your laptop. There is no account, no cloud control plane, no telemetry, and no hosted model provider. The optional AI layer uses Ollama with an open-weight model (default: &lt;code&gt;gemma2:2b&lt;/code&gt;), which means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No internet required.&lt;/strong&gt; The deterministic pipeline — scan, classify, hash duplicates, analyze logs, guard moves — works completely offline. The model is only needed for interpretation and workflow drafting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your data never leaves your machine.&lt;/strong&gt; Filenames, log signatures, and file contents stay in a local SQLite database and local reports. Nothing is uploaded, scanned by a third party, or used to train someone else's model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set it up once, never pay again.&lt;/strong&gt; Local inference costs nothing per token. There's no subscription, no API credit burn, and no rate limit from a hosted provider.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swap the model, fine-tune it, change the behavior.&lt;/strong&gt; Because the model talks to a standard Ollama endpoint, you can point GhostShift at any local model you prefer, swap in a fine-tuned version, or run it CPU-only. The AI is never an authority — it can't name a destination path, add a workflow action, or run a command. All it can do is suggest, and the application code decides whether to act.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Choice&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;Java 25, Micronaut 5.2, Gradle 9.8, Netty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;Vue 3 + TypeScript + Vite, Pinia, custom CSS design system&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;SQLite (WAL mode, direct JDBC)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI runtime&lt;/td&gt;
&lt;td&gt;Ollama (optional, local open-weight models)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Packaging&lt;/td&gt;
&lt;td&gt;Docker Compose (loopback-only ports)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The UI binds to &lt;code&gt;127.0.0.1:3000&lt;/code&gt;, the API to &lt;code&gt;127.0.0.1:8080&lt;/code&gt;, and both are loopback-only by default. An optional bearer token can lock the API down further.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Clone&lt;/span&gt;
git clone https://github.com/Senthil455/GhostShift-AI.git
&lt;span class="nb"&gt;cd &lt;/span&gt;GhostShift-AI

&lt;span class="c"&gt;# Configure&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
&lt;span class="c"&gt;# Edit .env if you want an API token or a different Ollama model&lt;/span&gt;

&lt;span class="c"&gt;# Run with Docker&lt;/span&gt;
docker compose up &lt;span class="nt"&gt;--build&lt;/span&gt;

&lt;span class="c"&gt;# UI:  http://127.0.0.1:3000&lt;/span&gt;
&lt;span class="c"&gt;# API: http://127.0.0.1:8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have Ollama running locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama serve
ollama pull gemma2:2b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open &lt;strong&gt;GhostBrain&lt;/strong&gt; in the UI and click &lt;strong&gt;Test model&lt;/strong&gt;. If Ollama isn't available, GhostShift still works — every deterministic feature runs without it, and AI-specific panels show an honest notice instead of inventing a result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;No browser or screen recording. GhostCapture records reviewed file actions only.&lt;/li&gt;
&lt;li&gt;No file deletion. Duplicate detection reports exact matches; it does not remove them.&lt;/li&gt;
&lt;li&gt;Docker images are packaged but were not runtime-tested in the build environment.&lt;/li&gt;
&lt;li&gt;Single-user local design — SQLite and an in-process worker are for one person on one machine.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Build it your way
&lt;/h2&gt;

&lt;p&gt;GhostShift is open source because the automation that touches your files should be inspectable, auditable, and yours to modify. If you want a sloth-speed automation studio that conserves your energy and keeps your data under your control, this is the repo to fork, extend, and run on your own hardware.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Senthil455/GhostShift-AI" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built for the Hacktoberfest Open-Source AI Challenge: Week 3 — "Slow and Steady."&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>automation</category>
    </item>
    <item>
      <title>SellCraft AI: a listing writer that runs on the seller's laptop, not my server</title>
      <dc:creator>Senthil raja .R</dc:creator>
      <pubDate>Mon, 19 Oct 2026 03:35:22 +0000</pubDate>
      <link>https://dev.to/senthil_raja_r/sellcraft-ai-a-listing-writer-that-runs-on-the-sellers-laptop-not-my-server-2pj6</link>
      <guid>https://dev.to/senthil_raja_r/sellcraft-ai-a-listing-writer-that-runs-on-the-sellers-laptop-not-my-server-2pj6</guid>
      <description>&lt;p&gt;(alt: SellCraft AI — a fully local Etsy/eBay listing writer with Gemma 4 and Ollama)&lt;br&gt;
&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;SellCraft AI is a listing writer that runs on the seller's laptop, not on anyone else's server.&lt;/strong&gt; A handmade seller drops in up to four product photos, types the few facts only the maker knows — materials, size, price — picks a platform (Etsy or eBay) and a tone, and gets back a finished listing: a keyword-front-loaded title inside the platform's character limit, a 120–180 word description in the shop's own voice, and tags that respect Etsy's 13-tags-by-20-characters rule.&lt;/p&gt;

&lt;p&gt;I built it for one specific person — the seller I kept picturing while writing it: forty active listings, a day job, a phone full of product photos. Photographing six new mugs takes an evening. &lt;em&gt;Writing the six listings takes another evening&lt;/em&gt;, and that's the evening the box stays closed and the mugs stay unlisted. SellCraft turns each listing into about a minute of work — and it doesn't sound like a template, because it writes from the photos and the seller's own words instead of from a blank prompt box.&lt;/p&gt;

&lt;p&gt;Would someone pay for it? I think so, and not much has to be true for that to hold: it saves a seller an evening a week, and it's sold as a flat one-time download. There's no API bill behind it, so there's no meter to hide inside a subscription — the seller can regenerate a description twenty times without watching a counter. Tooling for a side hustle shouldn't be one of the side hustle's fixed costs, and only a locally-running model makes that price possible.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;There's no live link, deliberately. SellCraft's whole argument is that it runs on the seller's machine — a hosted demo would be a different, worse product. The honest demo is two commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama pull gemma4      &lt;span class="c"&gt;# one-time: the model now lives on this machine&lt;/span&gt;
python sellcraft.py     &lt;span class="c"&gt;# opens http://127.0.0.1:8765&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The repo ships three sample photos (a mug, soap bars, earrings), so you can go from clone to a finished listing in about a minute without hunting for product photos.&lt;/p&gt;

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

&lt;p&gt;Everything lives in one repo: &lt;strong&gt;&lt;a href="https://github.com/Senthil455/Sell-Carft-AI" rel="noopener noreferrer"&gt;https://github.com/Senthil455/Sell-Carft-AI&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One Python file (~600 lines, standard library only), one plain HTML/CSS/JS front end, one SQLite file. No pip install, no build step, no framework, no account. Built end-to-end for this challenge.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;A single-file backend, on purpose.&lt;/strong&gt; The server is &lt;code&gt;http.server&lt;/code&gt; + &lt;code&gt;urllib&lt;/code&gt; + &lt;code&gt;sqlite3&lt;/code&gt; — every import is in Python's standard library. If you're going to ask a stranger to run AI on their own laptop, "you can read the entire backend in one sitting" is the feature. The trust story is the source code, not a policy page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gemma reads the photos.&lt;/strong&gt; The app talks to &lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt; on &lt;code&gt;127.0.0.1:11434&lt;/code&gt; and runs Gemma's vision model. Seeing the photo is what makes or breaks the output: it has to recognize speckled stoneware with a chunky handle, because "handmade ceramic mug" is the listing every other seller already has. Any vision model you've pulled shows up in a dropdown, so a slower laptop can swap down.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The prompt is where the product actually lives.&lt;/strong&gt; It's one carefully-built template with hard rules: never invent materials, sizes, prices or origins; work only from the seller's facts and what's clearly visible in the photos; plain text only; exactly four labelled sections (NOTES / TITLE / DESCRIPTION / TAGS). Each platform carries its own constraints — Etsy gets a 100–140 character title and 13 tags of ≤20 characters; eBay gets a keyword-first 80-character title and 8 keywords. My favourite part is NOTES: instead of inventing a size, the model says what it saw and asks about the one thing it couldn't read — "roughly how much does this hold?" A writer that asks is worth more than one that guesses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trust is enforced a second time, in code.&lt;/strong&gt; Prompts drift, so every draft passes through a &lt;code&gt;tidy_listing()&lt;/code&gt; cleanup before it reaches the UI: titles are truncated at a word boundary to the platform's limit, tags are deduplicated, lowercased and trimmed to 20 characters — and when trimming would gut a tag into nonsense, it's dropped instead of shipped broken. (Etsy silently ignores over-long tags, which is how sellers end up with nine working tags and no idea why.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Streaming, because good writing feels written.&lt;/strong&gt; The server relays Ollama's token stream to the browser, so you watch the title fill in, character counters tick against each platform's limits, and tags that run long light up red before Etsy ever sees them. A full draft lands in about &lt;strong&gt;[X] seconds at [Y] tok/s&lt;/strong&gt; on my laptop — the app prints both numbers under every draft, so the machine is honest about its speed with the seller.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It learns the shop's voice, locally.&lt;/strong&gt; Saved listings go into SQLite, and the last three are fed back into the next prompt as a style sample: &lt;em&gt;match this voice, never copy it.&lt;/em&gt; The output sounds more like the shop with every listing — and the examples never leave the machine that wrote them. Revision works the same way: type "less flowery" or "make the description shorter", and the model receives the previous draft plus the instruction, and rewrites the whole thing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Small kindnesses where they matter.&lt;/strong&gt; Photos are downscaled in the browser to 1000 px before they hit the local model. The app opens its own tab on startup. When Ollama isn't running, the page says so in plain words and offers a re-check button instead of dying. And there's a one-click CSV export, because a seller's catalogue is their business, not my database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it deliberately doesn't do:&lt;/strong&gt; it won't post to Etsy for you. The output is plain text with copy buttons, because holding a seller's marketplace credentials is a commitment a v1 shouldn't make. It's probably the first thing a real user will ask for — and that's a decision to make &lt;em&gt;with&lt;/em&gt; a real user, not on their behalf.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Privacy is the architecture, not a promise.&lt;/strong&gt; The only hostname that appears anywhere in SellCraft's source is &lt;code&gt;127.0.0.1&lt;/code&gt;. A handmade seller's photos are their original work — often photographed before the listing exists anywhere — and their drafts contain pricing and positioning they haven't published yet. Running Gemma locally means there is no server to trust. That's a different category of claim from "we don't store your data": you can verify it by reading one file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The business model only works because inference is local.&lt;/strong&gt; With a closed API, every draft is a line item, and the builder pays for every user forever. That cost structure is exactly what pushes small tools into subscriptions, credit packs, and "fair use" limits. Gemma on the laptop makes the hundredth listing cost the same as the first — nothing — so the product can be sold as a flat one-time download. A price that works for a seller in a craft economy only exists because the marginal cost is zero.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Swapping models is a feature, not an escape hatch.&lt;/strong&gt; The model dropdown is just "whatever you've pulled with Ollama." When a better open-weight vision model ships next month, a seller gets it with one command: no waitlist, no repricing, no migration project. Whole product roadmaps have been broken by a provider deprecating a single endpoint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The agent's behaviour is a text file.&lt;/strong&gt; "Never invent a size" is a visible rule in one f-string that a seller — or anyone forking the repo — can change in a line. Closed systems hand you a prompt box; open ones hand you the harness. And because Gemma's weights are open, the natural next step stays on the table instead of on a waitlist: fine-tuning a small model on a shop's own back catalogue, so the writer learns their &lt;em&gt;catalogue&lt;/em&gt; the way a hired copywriter would.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It works with the Wi-Fi off.&lt;/strong&gt; Once the model is pulled, SellCraft doesn't need the internet to write a listing — on a train, at a market stall, during an outage. That still feels slightly magic, and it's the property that most cleanly separates what open weights make possible from what closed APIs allow.&lt;/p&gt;

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

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

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

&lt;p&gt;&lt;strong&gt;Best Use of Gemma.&lt;/strong&gt; Gemma is the core of the product, running locally through Ollama: it reads the seller's photos and writes every word of the listing — the description, the title, the tags, and the questions it asks back. The default pull is &lt;code&gt;gemma4:latest&lt;/code&gt;; any Gemma vision build works, and there is no other model or cloud API anywhere in the stack.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>SunSeat: Touch Grass in 20 Minutes with Offline Gemma</title>
      <dc:creator>Senthil raja .R</dc:creator>
      <pubDate>Sun, 11 Oct 2026 18:22:42 +0000</pubDate>
      <link>https://dev.to/senthil_raja_r/sunseat-touch-grass-in-20-minutes-with-offline-gemma-39eh</link>
      <guid>https://dev.to/senthil_raja_r/sunseat-touch-grass-in-20-minutes-with-offline-gemma-39eh</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week1-2026-10-05"&gt;Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;SunSeat: a 20-minute sunny-bench finder for night-shift workers, SAD winters, and overstimulated brains. Enter location + minutes + needs (flat / quiet / toilet / shade / dog), get 3 sun pockets with a 0-100 go-now score + a 60-second mission card. Screen time under a minute, the rest is outside.&lt;/p&gt;

&lt;p&gt;I built it for myself in Chennai: short October evenings, no time for a hike, need sun fast without scrolling.&lt;/p&gt;

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

&lt;p&gt;Live: &lt;a href="https://sun-seat.onrender.com" rel="noopener noreferrer"&gt;https://sun-seat.onrender.com&lt;/a&gt; (verified &lt;code&gt;/api/health ok&lt;/code&gt;, frontend serves)&lt;br&gt;
Video (90s): screen search -&amp;gt; walk -&amp;gt; sunny bench -&amp;gt; mission card read aloud (narration in &lt;code&gt;demo-narration.txt&lt;/code&gt;, MP3 via ElevenLabs).&lt;br&gt;
Offline proof: load once online, airplane mode on, reload &lt;code&gt;/&lt;/code&gt; - results render from &lt;code&gt;localStorage sunseat_last&lt;/code&gt;. Screenshot in repo &lt;code&gt;docs/&lt;/code&gt; after you test.&lt;br&gt;
Cover: &lt;code&gt;frontend/cover.svg&lt;/code&gt; (1000x420).&lt;/p&gt;

&lt;p&gt;Local fallback if needed: &lt;code&gt;pip install -r requirements.txt &amp;amp;&amp;amp; uvicorn backend.main:app --port 8000&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;Repo: &lt;a href="https://github.com/Senthil455/Sun-Seat" rel="noopener noreferrer"&gt;https://github.com/Senthil455/Sun-Seat&lt;/a&gt; (MIT)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;backend/main.py&lt;/code&gt; - FastAPI, solar math, OSM Overpass, Open-Meteo, &lt;code&gt;best_hour_tabpfn()&lt;/code&gt;, &lt;code&gt;gemma_brief()&lt;/code&gt; via Ollama&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;frontend/index.html&lt;/code&gt; - single-file PWA, offline cache, free TTS Speak button&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scripts/tabpfn_demo.py&lt;/code&gt; + &lt;code&gt;data/weather_history.csv&lt;/code&gt; - TabPFN evidence, CI check&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tests/test_api.py&lt;/code&gt; - 3 tests, all passing&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Dockerfile&lt;/code&gt; + &lt;code&gt;render.yaml&lt;/code&gt; + &lt;code&gt;.github/workflows/ci.yml&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Open core, not decoration:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Gemma via Ollama writes the mission card. Prompt + output logged in &lt;code&gt;/api/brief&lt;/code&gt;. Local run returns &lt;code&gt;mode:local-open-weight&lt;/code&gt; - proof in &lt;code&gt;docs/ollama-proof-gemma2-2b.json&lt;/code&gt; (full &lt;code&gt;gemma2:2b&lt;/code&gt;, tested on laptop; &lt;code&gt;docs/ollama-proof.json&lt;/code&gt; shows the lighter &lt;code&gt;gemma3:270m&lt;/code&gt; swap). Render free has no GPU/Ollama so it returns an honest &lt;code&gt;hosted-template-fallback&lt;/code&gt; - cite the proof files as evidence.&lt;/li&gt;
&lt;li&gt;OSM Overpass supplies parks / benches / toilets + &lt;code&gt;surface/smoothness/incline&lt;/code&gt; tags. Open-Meteo supplies cloud + radiation. Pure-python solar elevation + transparent &lt;code&gt;sun_score()&lt;/code&gt; 0-100.&lt;/li&gt;
&lt;li&gt;TabPFN: &lt;code&gt;scripts/tabpfn_demo.py&lt;/code&gt; trains &lt;code&gt;TabPFNRegressor&lt;/code&gt; on &lt;code&gt;data/weather_history.csv&lt;/code&gt; when installed, else sklearn fallback with stderr log. Backend &lt;code&gt;best_hour_tabpfn()&lt;/code&gt; does the same live. Run &lt;code&gt;python scripts/tabpfn_demo.py --json&lt;/code&gt; and paste output.&lt;/li&gt;
&lt;li&gt;SerpApi &lt;code&gt;/api/foliage&lt;/code&gt;: live search when &lt;code&gt;SERPAPI_KEY&lt;/code&gt; set, else &lt;code&gt;cached-offline&lt;/code&gt;. Sentry inits when &lt;code&gt;SENTRY_DSN&lt;/code&gt; set - paste trace + &lt;code&gt;latency_ms&lt;/code&gt; from &lt;code&gt;/api/pockets&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Swap models in one var: &lt;code&gt;OLLAMA_MODEL=llama3.2:1b&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;Closed maps hide the tags I filter on - surface, smoothness, bench, toilets. I cannot build flat/quiet/toilet search on Google Maps API. OSM exposes them freely.&lt;/p&gt;

&lt;p&gt;Closed AI dies on the trail: needs signal, per-token cost, uploads your location + photo. SunSeat caches OSM + weather JSON after first fetch, then Gemma 2B runs on the laptop with no internet, $0, private. I edited the prompt locally, swapped models, no approval, no bill. That offline airplane-mode run is the whole point - and only possible open.&lt;/p&gt;

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

&lt;p&gt;Built with GitHub Copilot CLI + this coding agent. Process evidence: commit history + CI run &lt;code&gt;.github/workflows/ci.yml&lt;/code&gt; (health + tabpfn check). Screenshots attached: Ollama &lt;code&gt;mode:local-open-weight&lt;/code&gt; brief, airplane-mode reload.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Best Use of Gemma (local &lt;code&gt;gemma2:2b&lt;/code&gt; mission card)&lt;/li&gt;
&lt;li&gt;Best Use of Render (Dockerfile + live URL)&lt;/li&gt;
&lt;li&gt;Best Use of TabPFN (CSV forecast, &lt;code&gt;scripts/tabpfn_demo.py&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Best Use of SerpApi (live foliage grounding / cached fallback)&lt;/li&gt;
&lt;li&gt;Best Use of GitHub Copilot (Copilot CLI + Actions CI)&lt;/li&gt;
&lt;li&gt;Best Use of ElevenLabs (&lt;code&gt;demo-narration.txt&lt;/code&gt; -&amp;gt; MP3 narration)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
