AuvroAI banner

AuvroAI

25 devlogs
26h 49m 13s

AuvroAI is a desktop AI chat app written in Rust with a focus on fast startup, local-first responsiveness, streaming chat, and measurable optimization work.

This project uses AI

Gemini for README.md, Claude for debugging, GitHub Copilot for code completion and ChatGPT for Scripts to build app (The files in tools folder)

Demo Repository

Loading README...

anup34343

I replaced the settings experience with a dedicated central panel that opened from the chat avatar menu, and I wired section-scoped actions for display name, email, password, photo, theme, and account deletion with disabled-save guards and inline status rendering. I moved the profile menu trigger to the chat top-right avatar and kept settings state in AppState so updates were applied through explicit async events instead of ad hoc UI mutations. For auth reliability, I fixed the login 404 by switching password sign-in to /auth/v1/token?grant_type=password and sending Content-Type, apikey, and Authorization bearer publishable-key headers expected by GoTrue. I implemented profile persistence against a public.profiles table keyed by auth.users.id with display_name, avatar_url, theme, and updated_at fields, and I used PATCH calls for targeted updates plus storage object upload for avatars. I tightened database security with explicit RLS policies for select, insert, and update using auth.uid() = id, and I documented a backfill query for existing auth users that were missing profile rows. I removed the client-side profile ensure-insert path that had produced 403/42501 errors and returned clear errors when a PATCH matched zero rows so missing-profile setup was diagnosable. I also cleaned compiler warnings by adding #[allow(dead_code)] on model_cache, #[allow(dead_code)] on upsert_profile, and a module-level #![allow(dead_code)] in model_metadata to silence currently unwired cache constants, enum variants, struct fields, and helper methods without changing runtime behavior.

Attachment
0
anup34343

I finished the README overhaul so it now describes the app clearly, documents setup and environment variables, explains the optimization work with before/after benchmark tables, and includes installer build instructions for Windows, Linux, and macOS. I also finalized the release packaging path across platforms: Windows MSI now builds locally with cargo-wix and WiX Toolset, Linux DEB packaging is configured through cargo-deb with Debian metadata and desktop integration, and macOS DMG packaging is documented through cargo-bundle plus create-dmg. To make the process reproducible, I added a GitHub Actions workflow for native installer builds and small helper scripts under tools/ for each platform so the packaging steps are easy to rerun. The result is a cleaner project handoff: the README tells the story of the app and its optimizations, and the build pipeline now covers all three desktop targets.

Attachment
0
anup34343

I finished the README overhaul so it now describes the app clearly, documents setup and environment variables, explains the optimization work with before/after benchmark tables, and includes installer build instructions for Windows, Linux, and macOS. I also finalized the release packaging path across platforms: Windows MSI now builds locally with cargo-wix and WiX Toolset, Linux DEB packaging is configured through cargo-deb with Debian metadata and desktop integration, and macOS DMG packaging is documented through cargo-bundle plus create-dmg. To make the process reproducible, I added a GitHub Actions workflow for native installer builds and small helper scripts under tools/ for each platform so the packaging steps are easy to rerun. The result is a cleaner project handoff: the README tells the story of the app and its optimizations, and the build pipeline now covers all three desktop targets.

Attachment
0
anup34343

Optimization Technique 5 - Optimize release binary size and speed

Release profile changes

Applied in Cargo.toml:

  • lto = "thin"
  • codegen-units = 1
  • strip = "symbols"
  • panic = "abort"

panic = "abort" is acceptable here because the app relies on normal Result-based error handling for network, auth, and UI flows, and the build completed successfully in both debug and release configurations.

Binary size delta

Baseline after dependency:

  • Release: 23.83 MB

After release profile optimization:

  • Release: 19.91 MB

Delta:

  • 3.92 MB smaller
  • 16.45% reduction

Notes

  • upx is not installed in this environment, so the optional UPX step was not applied.
Attachment
0
anup34343

Optimization Technique 4 - Minimize dependencies

Audit command

  • Ran cargo +nightly udeps --all-targets.
  • Result: All deps seem to have been used.

Dependency and feature pruning applied

  • Removed unused direct dependency:
    • sysinfo
  • Removed explicit platform wgpu dependencies from Cargo.toml (already provided through eframe with wgpu feature).
  • Disabled default features where safe to reduce transitive graph:
    • egui_commonmark: default-features = false
    • tokio: default-features = false (kept rt-multi-thread, time)
    • tokio-util: default-features = false (kept rt)
    • uuid: default-features = false (kept serde, v4)
  • Narrowed image features from broad defaults to only required decoders:
    • default-features = false
    • features = ["png", "jpeg", "gif", "webp"]

Binary size delta

Baseline

  • Release (no optimizations): 30.47 MB

After pruning (current):

  • Release: 23.83 MB (target/release/AuvroAI.exe)

Delta:

  • 6.64 MB smaller
  • 21.79% reduction
Attachment
0
anup34343

Technique 3 - Reduce memory allocations

Audit summary

  • Audited allocation hot paths in main::tick_streaming and chat_pipeline::read_streaming_response.
  • Removed needless full-buffer clone in streaming (message.content = streaming_buffer.clone()) and switched to chunk append (message.content.push_str(&next_chunk)).
  • Kept a reusable Vec<u8> buffer in SSE parsing loop and removed per-line owned String allocation where not required.
  • Migrated immutable request message fields to Arc<str> in chat pipeline/provider path to reduce repeated String cloning.

Peak RSS measurement (before vs after)

Metric : Value

Before peak RSS : 17108.00 MB
After peak RSS : 16304.00 MB
Delta : 804.00 MB lower

Attachment
0
anup34343

Optimization Technique 2 - Lazy loading of heavy resources

What was changed

  • Session history stays lazy: conversation messages are only loaded when a session is opened (request_load_messages on selection).
  • Model metadata stays lazy: metadata fetch is triggered when the Settings screen is opened (model_cache.ensure_loaded(...)).

Measurement

Here is the quick breakdown:

  • Startup Time: Lazy is 1130 ms faster (0 ms vs. 1130 ms).
  • Memory (RSS): Lazy is 5880 MB lower (13.9 GB vs. 19.8 GB).

Lazy loading offers an instant start and a 30% reduction in initial memory overhead.

Notes

  • Eager scenario simulated startup-time heavy fetches (model metadata and one session-history preload attempt where credentials were available).
  • Lazy scenario skipped heavy fetches during startup and deferred them until user interaction.
Attachment
0
anup34343

Optimization Technique 1 - Application-level response cache

  • Cache key: blake3::hash(prompt + model + system_prompt)
  • TTL: 600 seconds (env AUVRO_CACHE_TTL_SECS, default 600)
  • Max cache size: 50 MB (env AUVRO_CACHE_MAX_MB, default 50)

Measurement

Metric: Value
Cache hits: 24
Cache misses: 6
Cache hit ratio: 80.00%
P50 uncached: 1838 ms
P50 cached: 0 ms
P50 delta: 1838 ms

Attachment
0
anup34343

Before optimizations benchmark results

Captured before any optimizations.
Rust toolchain: rustc 1.94.1 (e408947bf 2026-03-25)
Platform: Windows 11 (26100) | CPU: AMD EPYC 7763 64-Core Processor
Date: 2026-04-15

Latency (100 sequential prompts, no streaming)

Metric Value P50 220 ms P95 225 ms P99 242 ms Average 220 ms Failures 100/100

Memory (10 concurrent requests)

Metric Value Idle RSS 21304.00 MB Peak RSS 22088.00 MB Delta 784.00 MB

Binary size

Build Size Debug 54.01 MB Release (no optimizations) 30.47 MB
Attachment
0
anup34343

I rebuilt the chat screen around a left sidebar for the conversation list, a centered main chat panel, and a compact top bar that showed the conversation title alongside the avatar and logo. I rendered user messages as right-aligned filled bubbles and assistant messages as left-aligned plain text, while adding markdown support with CommonMarkViewer and emoji support through a loaded color emoji font so replies displayed cleanly. I drove streaming with an mpsc channel, polled it each frame with try_recv, and updated the assistant buffer incrementally so the UI stayed responsive during token arrival. I kept the scroll area pinned to the bottom for new output, but I paused the auto-scroll behavior whenever the user moved back through history. I also added an empty-state placeholder for when no conversation was active so the panel still felt intentional instead of blank. At the bottom, I kept the composer anchored with a multiline text box and explicit Send and Stop buttons so composing, streaming, and cancellation stayed in one predictable layout.

Attachment
0
anup34343

I implemented the chat screen using an egui shell with a left SidePanel for the conversation list, a CentralPanel for the active thread, and a compact top bar that showed the selected conversation title alongside the profile avatar and menu trigger. I rendered messages with role-specific layout rules by pushing user entries to a right-aligned, filled bubble frame while drawing assistant entries left-aligned with plain text styling and lighter visual chrome to keep reply scanning fast. I wired token streaming through an mpsc receiver and polled it every frame with try_recv inside the update path so incremental chunks appended without blocking input or repaint cadence. I configured auto-scroll with a bottom-stick policy that followed new content while the viewport remained near the end, and I paused forced scrolling when user-driven scroll offset moved upward so manual history inspection stayed stable. I added an empty-state placeholder for the no-active-conversation case, using centered labels and quick-start prompt actions to avoid a blank panel and to guide first interaction flow. I finished the composer as a bottom-anchored input row with multiline TextEdit behavior plus explicit Send and Stop buttons, with enabled-state guards tied to loading and stream status to prevent conflicting submit/cancel actions.

Attachment
0
anup34343

I rebuilt the auth screen as a two-panel split layout with a peach left panel featuring decorative shapes and speech bubbles, and a white right panel that holds the form. I centered the form within the right panel, kept the card compact, and aligned the tab selector, inputs, and primary button in a clean vertical flow. I fixed the eye icon inside the password field by rendering it in a dedicated overlay slot and aligning its hit target to the icon bounds so toggling no longer clips. I hit a borrow checker error when drawing with ui.painter() while mutating the UI, so I moved background decoration and foreground icon drawing to ctx.layer_painter() on separate background and foreground layers. That split allowed me to keep UI layout mutations and custom painting independent without aliasing. The final layout reads as a warm illustrated left column and a crisp form-focused right column with stable input interactions.

Attachment
0
anup34343

I replaced the settings experience with a dedicated central panel that opened from the chat avatar menu, and I wired section-scoped actions for display name, email, password, photo, theme, and account deletion with disabled-save guards and inline status rendering. I moved the profile menu trigger to the chat top-right avatar and kept settings state in AppState so updates were applied through explicit async events instead of ad hoc UI mutations. For auth reliability, I fixed the login 404 by switching password sign-in to /auth/v1/token?grant_type=password and sending Content-Type, apikey, and Authorization bearer publishable-key headers expected by GoTrue. I implemented profile persistence against a public.profiles table keyed by auth.users.id with display_name, avatar_url, theme, and updated_at fields, and I used PATCH calls for targeted updates plus storage object upload for avatars. I tightened database security with explicit RLS policies for select, insert, and update using auth.uid() = id, and I documented a backfill query for existing auth users that were missing profile rows. I removed the client-side profile ensure-insert path that had produced 403/42501 errors and returned clear errors when a PATCH matched zero rows so missing-profile setup was diagnosable. I also cleaned compiler warnings by adding #[allow(dead_code)] on model_cache, #[allow(dead_code)] on upsert_profile, and a module-level #![allow(dead_code)] in model_metadata to silence currently unwired cache constants, enum variants, struct fields, and helper methods without changing runtime behavior.

Attachment
0
anup34343

I migrated chat history persistence to Supabase by implementing conversations and messages tables with UUID primary keys, timestamp columns, and a foreign key from messages.conversation_id to conversations.id with cascade delete behavior. I wired the application to list conversations by updated_at, load per-conversation message history, append both user and assistant messages through PostgREST, and bump conversations.updated_at so active threads stayed correctly ordered. I aligned row-level security so conversation access enforced auth.uid() = user_id and message access was constrained to rows whose conversation belonged to the authenticated user. I cleaned up compiler warnings without changing behavior by adding targeted #[allow(dead_code)] attributes for intentionally retained but currently unused items, including rename_conversation, ModelInfo.provider, set_failed, and generate_reply_with_system_prompt. I eliminated constant-level warning noise in the chat pipeline by renaming placeholder defaults to underscore-prefixed identifiers and annotated the max_context_tokens field to keep the request structure stable while suppressing dead-code diagnostics. I fixed the login 404 by moving password sign-in to the exact GoTrue endpoint SUPABASE_URL/auth/v1/token?grant_type=password and enforcing the required Content-Type and apikey headers, plus Authorization: Bearer SUPABASE_PUBLISHABLE_KEY for sign-in and refresh flows. I added eprintln! diagnostics for the full login request URL and response status, and validation returned a Supabase invalid_credentials 400 instead of nginx 404, confirming the auth path and header composition were corrected.

Attachment
0
anup34343

I implemented a Linux release packaging path by documenting the exact native dependencies required by eframe and winit in the README, which removed ambiguity for fresh Ubuntu and Debian setups. I configured the desktop build dependency to eframe = { version = "*", features = ["default_fonts"] } so the release binary included the expected font support without extra runtime setup. I compiled the app with cargo build --release, which produced a single optimized executable at target/release/auvro_ai for local testing and distribution. I validated execution by applying executable permissions and launching the binary directly, and I confirmed the runtime failure mode in headless environments was display-related rather than a build artifact issue. I kept the workflow deterministic by relying on compile-time environment constants, so the binary behavior matched the exported .env values used during compilation.

Attachment
0
anup34343

I implemented Supabase-backed chat persistence for AuvroAI by moving chat history from local in-memory state to database-backed sessions and messages. On app load, the client now fetches all sessions for the authenticated user ordered by updated_at and shows them in the sidebar, and selecting any session loads its full message history from Supabase into the chat view. For a new chat, the first user message triggers session creation first, then message insertion, and all following user and assistant messages are stored under the same session_id while updated_at is refreshed so recent chats stay on top. I also added automatic chat title generation by sending the first user message through a title-specific system prompt and saving the returned short title to sessions.title, plus an empty-state UI that shows greeting/new-chat prompts when no sessions exist and transitions to the normal chat layout as soon as a conversation starts.

Attachment
0
anup34343

Added a settings page to AuvroAI so authenticated users can view their profile picture, name, and email, and update their account details from one place. The chat UI now shows a circular profile button on the right side of the header, and clicking it opens the account menu with Settings and Log Out actions. This makes the app feel more complete and gives the user a clearer place to manage their profile from inside the chat experience.

Attachment
0
anup34343

Completed the Phase 3 chat request pipeline by adding a shared streaming request layer with system prompt injection, token-budget-aware sliding context assembly, SSE/chunk parsing, timeout handling, exponential backoff retries, and cancellation token checks for in-flight calls. Refactored both HackClub and OpenRouter providers to use the same pipeline so request behavior is consistent across backends and easier to maintain. Rebuilt the Linux app bundle after the refactor so the updated response pipeline can be tested directly in the packaged desktop app.

Attachment
0
anup34343

Added provider failover so AuvroAI tries HackClub AI first and automatically falls back to OpenRouter if the primary backend rate limits or fails. The provider layer now supports both backends through the same abstraction, with OpenRouter configured as a free-tier backup model and the HackClub/OpenRouter request shapes aligned to the current system prompt flow. Rebuilt the Linux test package so the updated AI backend behavior can be tested in the bundled app.

Attachment
0
anup34343

Started Phase 3 AI Core by introducing a unified Provider abstraction and routing chat generation through that interface instead of hardcoded response logic in the UI layer. Added a HackClub AI provider implementation configured via environment variables, using the HackClub proxy base URL pattern and OpenAI-compatible chat completions payloads. Also added a structured system prompt block to establish assistant identity and startup behavior, then rebuilt the Linux test package so the latest provider-backed flow can be validated in the bundled app.

Attachment
0
anup34343

Expanded the auth flow with a clear Log In / Sign Up switch so the desktop app shows the right fields for each path. Log In now asks for email and password, while Sign Up collects full name, email, password, and password confirmation with validation before sending. This keeps the Supabase auth flow cleaner and makes the redirect into chat feel more like a real app experience.

Attachment
0
anup34343

Added an auth system for AuvroAI with Supabase-backed email login and signup flows, plus session restore and logout so the app redirects into chat only when the user is authenticated. The auth UI now switches between Log In and Sign Up modes, and the signup flow collects full name, email, password, and password confirmation. Also tightened secret handling by loading Supabase config from the app bundle or secure storage instead of exposing it in the interface.

Attachment
0
anup34343

Enhanced the desktop UI with clearer theming, improved typography scale, better spacing, and stronger accessibility-focused contrast so the interface is easier to scan and use. Upgraded local session management to support create, rename, and delete flows with per-session message history, making chat organization much more practical. Fixed compile issues from the refactor and produced a fresh Linux package so the updated experience can be tested immediately.

Attachment
0
anup34343

Improved the chat experience by adding Enter-to-send with Shift+Enter for new lines, keeping the composer fast while still supporting multiline input. The message flow now feels more natural with streaming assistant output, a visible typing indicator, and inline error feedback controls. Also refreshed the Linux test package so the latest interaction behavior can be validated directly from the bundled app build.

Attachment
0
anup34343

Created the base of the project with a working Rust desktop chat app shell, including sessions sidebar, main chat panel, and a simple quick-start side panel. Enabled no-key chat flow so users can open the app and start messaging immediately without setup. Added Linux test packaging with a release binary, launcher script, desktop entry file, and compressed tarball for easy local testing.

Attachment
0