DEV Community

Cover image for Soul in Motion — 3:06 PM | 2026-08-27
Dev Rajput
Dev Rajput

Posted on

Soul in Motion — 3:06 PM | 2026-08-27

TL;DR

  • Re‑engineered Horizon’s auth flow to be both secure and user‑friendly, adding graceful error handling for mistyped passwords, dropped connections, and double submissions.
  • Experimented with a Rails‑based LLM that auto‑generates code from plain‑English descriptions; early results show promise but still need refinement.
  • Audited Eli’s UX to eliminate friction points, enabling seamless re‑entry after breaks and reducing silent churn.
  • Added six customizable “rooms” (light/dark, warm/quiet) to Eli, giving users contextual environments that influence comfort and engagement.
  • The core mantra, “Free AI can answer you. Eli is built to hold you.”, drives every design and implementation decision.

Re‑thinking Authentication in Horizon

The first half of the day was all about the login flow. I had been iterating on Horizon’s authentication for weeks, each pass tightening security while shaving latency. The last iteration finally felt right: a single‑page login that validates credentials via a GraphQL mutation, then issues a short‑lived JWT and a refresh token stored in an HTTP‑only cookie.

Graceful Failure

What really mattered was the experience when something went wrong. Instead of a generic “invalid credentials” page, I wrapped the mutation in a try/catch block that catches:

  • AuthenticationError – wrong password
  • NetworkError – dropped connection
  • ValidationError – double submission

Each error maps to a specific, user‑friendly message:

def handle_login_error(error)
  case error
  when AuthenticationError
    flash.now[:alert] = "That username or password doesn't match our records."
  when NetworkError
    flash.now[:alert] = "Connection lost. Please check your internet and try again."
  when ValidationError
    flash.now[:alert] = "We detected a duplicate request. Please wait a moment."
  else
    flash.now[:alert] = "Something went wrong. Try again later."
  end
end
Enter fullscreen mode Exit fullscreen mode

The messages are intentionally vague enough to avoid giving attackers hints, yet specific enough to guide legitimate users. I also added a debounce on the submit button to prevent double submissions at the UI level.

Invisible but Critical

These changes are buried three layers deep: the GraphQL resolver, the Rails controller, and the front‑end component. No one sees them unless something breaks, but when they do, the system fails kindly. That’s the kind of invisible kindness I like to build.


Rails + LLM: Turning Sentences into Code

After Horizon settled, I dove into a side project: a Rails app that uses an LLM to generate Ruby code from plain‑English prompts. The goal is to prototype a “code‑as‑service” layer that could one day power Eli’s dynamic room generation.

Architecture

  • Prompt Engine – a thin wrapper around OpenAI’s gpt-4o-mini API.
  • Code Validator – runs the generated code through rubocop and a unit‑test harness to catch syntax errors.
  • Feedback Loop – user corrections are fed back into the prompt to improve future generations.
# Gemfile
gem 'openai', '~> 3.0'
gem 'rubocop', '~> 1.50'
Enter fullscreen mode Exit fullscreen mode
class CodeGenerator
  def initialize(prompt)
    @prompt = prompt
  end

  def generate
    response = OpenAI::Client.new.chat(
      model: "gpt-4o-mini",
      messages: [
        { role: "system", content: "You are a helpful Ruby developer." },
        { role: "user", content: @prompt }
      ]
    )
    response.dig("choices", 0, "message", "content")
  end

  def validate(code)
    result = RuboCop::Runner.new([], []).run(code)
    result.empty?
  end
end
Enter fullscreen mode Exit fullscreen mode

Early Results

The model sometimes produces a working snippet on the first try, especially for straightforward tasks like “create a Rails migration for a users table.” More complex logic, like a service object that interacts with an external API, still requires a few rounds of correction. Still, the fact that it can generate a complete method from a single sentence is a glimpse of what a future AI‑assisted developer might look like.


Eli: From One Room to Six

Eli is a conversational companion built on top of the same authentication stack. The second half of the day was dedicated to polishing the user journey.

UX Audit

I walked through every point where a user might silently lose interest:

  • Session Expiry – implemented silent refresh using the refresh token.
  • Navigation Gaps – added “Continue where you left off” prompts.
  • Onboarding – simplified the first‑time flow to a single screen.

These fixes reduce friction and keep users engaged.

The Six Rooms

The real fun came with the “rooms” feature. Each room is a pre‑configured set of UI themes and background audio that changes the user’s context:

Room Theme Audio
1 Light, warm Café chatter
2 Dark, quiet Library hush
3 Light, cool Beach waves
4 Dark, warm Fireplace crackle
5 Light, neutral City traffic
6 Dark, cool Night sky

The implementation is a simple Rails view component that swaps CSS variables and plays an audio stream via the Web Audio API.

class RoomComponent < ViewComponent::Base
  def initialize(room:)
    @room = room
  end

  def theme_css
    @room.theme_css
  end

  def audio_url
    @room.audio_url
  end
end
Enter fullscreen mode Exit fullscreen mode
<div class="room" style="<%= theme_css %>">
  <audio autoplay loop src="<%= audio_url %>"></audio>
  <%= render @content %>
</div>
Enter fullscreen mode Exit fullscreen mode

Users can switch rooms on the fly, and the app remembers their last choice in a user_room column on the users table.


The Core Mantra

A line I’d written weeks ago kept resurfacing: “Free AI can answer you. Eli is built to hold you.” That sentence is the north star for every decision:

  • Free AI – the LLM that powers code generation and conversational responses.
  • Hold you – the gentle error handling, the frictionless re‑entry, the comforting rooms.

Everything else—login flow, six rooms, quiet error messages—serves that promise.


Evening Reflections

I wrapped up the day with a mix of media: Rick and Morty for a dose of chaos, Boardwalk Empire for sharp dialogue, a Joe Rogan clip for a lighter tone, and an unexpected America’s Got Talent episode that actually kept me engaged. It’s a reminder that even when the code is solid, life still needs a little entertainment.


Looking Ahead

  • Horizon – still adding analytics to monitor authentication success rates and failure reasons.
  • LLM Code Generator – need to improve the feedback loop and add a sandbox for safe execution.
  • Eli – rooms are built, but I’ll start A/B testing to see which environments drive the most engagement.

The system that used to fail loudly now fails kindly, and a companion that had one room now has six. Tomorrow I’ll test whether these changes hold up under real traffic and user feedback.

Top comments (0)