DEV Community

Cover image for I Got Tired of Fixing the Same Flutter Error Twice — So I Built StackSoothe
Joy
Joy

Posted on

I Got Tired of Fixing the Same Flutter Error Twice — So I Built StackSoothe

Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady Submission 🦥

This is a submission for the Hacktoberfest Open-Source AI Challenge: Slow and Steady.


What I built

If you develop with Flutter, you may know the frustration of spending half an hour debugging an error, fixing it, and then meeting the same problem again a few months later.

Maybe it is a use_build_context_synchronously warning, a LateInitializationError, or a RenderFlex overflow. The routine can feel familiar: copy the stack trace, search for an explanation, share a code snippet with an AI assistant, sort through suggestions, and work out the fix again.

I built StackSoothe, a local-first debugging assistant for Flutter and Dart developers. It uses a local open-weight model to diagnose an error the first time. Once I have checked the advice and explicitly marked the fix as verified, StackSoothe can remember that solution and retrieve it when the same error and context recur.

┌─────────────────────────────────┐
│     StackSoothe Desktop App     │  (Flutter / Dart Windows Runner)
│   - Fix Notebook (%LOCALAPPDATA%)│
│   - Deterministic SHA-256 Keys  │
└────────────────┬────────────────┘
                 │ HTTP (127.0.0.1:11435) with Ephemeral Bearer Token
                 ▼
┌─────────────────────────────────┐
│   Local Node/TypeScript Service │  (Single-concurrency loopback shim)
│   - Exact Host Header Validation │
│   - Strict Zod Schema Validation │
└────────────────┬────────────────┘
                 │ HTTP (127.0.0.1:11434)
                 ▼
┌─────────────────────────────────┐
│          Local Ollama           │  (qwen3:1.7b, 100% Local Inference)
└─────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

The idea is simple: do the difficult diagnosis once, apply human judgment, and avoid repeating the same work unnecessarily.

The “Slow and Steady” payoff

StackSoothe follows five steps:

  1. Diagnose locally. Paste a runtime error and relevant source context. StackSoothe sends them to qwen3:1.7b, running locally through Ollama, and asks for a structured diagnosis with a likely cause, suggested steps, severity, and confidence.
  2. Keep a human in the loop. Every new diagnosis begins as UNVERIFIED. The model cannot mark its own answer as a confirmed fix; the developer must do that.
  3. Fingerprint the problem. When a fix is verified, StackSoothe computes a SHA-256 fingerprint from the canonicalized error, source context, and project/runtime details.
  4. Recall an exact repeat. When that fingerprint matches a verified record, StackSoothe retrieves the saved solution without another model call.
  5. Be cautious about changed context. If the error appears in a different project, modified source context, or a changed runtime environment, StackSoothe warns that the old fix may be stale instead of silently reusing it.

In the current synthetic benchmark, an exact repeat lookup took 1.98 milliseconds and avoided another model call. That is a measured lookup result, not a claim that every debugging task will be solved in milliseconds: the initial model diagnosis is much slower.

Demo and source code

Demo video:

The 2-minute walkthrough demonstrates:

  1. First-occurrence diagnosis via local qwen3:1.7b (initial state: UNVERIFIED).
  2. Explicit developer verification of the proposed fix.
  3. Retrieval of a verified solution on an exact recurrence, without another model call.
  4. A warning when the same error appears with modified source context.
  5. Source repository:

    StackSoothe — Local Flutter & Dart Debugging Assistant

    License: MIT Release: v0.1.0-challenge Platform: Windows x64 Theme: Slow and Steady

    StackSoothe is an open-source, local-first debugging assistant for Flutter and Dart developers. Built around the Hacktoberfest 2026 "Slow and Steady" theme, it eliminates redundant manual troubleshooting: paste confusing runtime logs once, receive an honest structured diagnosis from a local open-weight model, verify the fix locally, and recall verified solutions upon future recurrences with zero additional model inference (under 2 ms).


    The "Slow and Steady" Payoff

    Flutter developers repeatedly encounter identical runtime failures (e.g. BuildContext used across async gaps, null-check operators on uninitialized fields, RenderFlex layout overflows). Re-explaining the same error to a chat interface or searching old forum threads is tedious, unwanted work.

    StackSoothe automates that repetition:

    1. First Occurrence: Diagnosed locally by qwen3:1.7b running on Ollama. The report details likely cause, actionable fix steps, severity, and confidence.
    2. User Verification: Diagnosis starts UNVERIFIED. Only an explicit human action transitions it…
  6. Windows standalone release: v0.1.0-challenge Package (45.8 MB)
  7. License: MIT License

The Windows preview is an unsigned release candidate. It requires Ollama and the qwen3:1.7b model; follow the repository quick-start instructions before running it.

How I built it

StackSoothe has three main pieces:

  • Flutter desktop app: the Windows interface and local Fix Notebook.
  • Node.js/TypeScript service: a small local service that validates requests and responses before and after model inference.
  • Ollama with qwen3:1.7b: local open-weight inference for the first diagnosis.

The service binds to 127.0.0.1:11435 and communicates with Ollama at 127.0.0.1:11434. It uses an ephemeral bearer token, validates host and origin information, and checks model output against a strict Zod schema. The private desktop flow is designed to keep source snippets, stack traces, and stored fixes on the developer's machine. Offline diagnosis works after Ollama and the model have been installed.

There is one important privacy trade-off: the Fix Notebook is stored as local JSON and is not encrypted at rest. It relies on the operating system's file permissions. I wanted that limitation to be explicit rather than describing local storage as automatically secure in every respect.

A bug I found while instrumenting diagnosis

During tracing work, I found an edge case where a timed-out model request could be reported as if the user had cancelled it. The schema-validation failure path could also discard useful token and timing metrics. I updated the abort-signal handling to distinguish timeouts from user cancellation and preserved the timing metadata when schema validation fails. Regression tests were added for those cases.

How I evaluated it

The repository's current evaluation documentation describes 12 predeclared synthetic cases: eight diagnostic cases and four state/reuse cases. The recorded results include:

  • Raw schema validity: 8/8 diagnostic cases.
  • Schema validity after at most one repair retry: 8/8 diagnostic cases.
  • Semantic checks for groundedness, uncertainty handling, and prompt-injection safety: 8/8 diagnostic cases.
  • State and reuse checks: 4/4 cases.
  • Exact repeat recall: 1.98 ms, with no new model call for the measured exact matches.

On the recorded Windows 11 test machine with 16 GB RAM and shared Intel UHD graphics, cold-start latency was 50.8 seconds. Warm inference had a reported median of 74.1 seconds, with a range of 46.8–100.1 seconds. These timings depend on the machine and model state; local inference is not necessarily faster than a hosted model.

No external human developer trial has been conducted. These results are limited to synthetic cases and machine measurements. They demonstrate the behavior tested so far, not proven improvements in developer productivity across a wider population.

Why open innovation matters

The local model is not an optional chatbot bolted onto a conventional debugger. It performs the initial diagnosis that starts the workflow.

Open-weight models and local inference matter to StackSoothe for three reasons:

  • Privacy and control: source code and stack traces from private projects can be sensitive. After initial model setup, the diagnosis flow can run locally without sending those inputs to a hosted AI provider.
  • Model choice: developers can inspect the setup and replace the model or adjust the prompt and output schema instead of depending on a remote provider's API behavior.
  • Less repeated computation: once a developer verifies a fix, an exact recurrence can use the local notebook rather than making another inference request. This avoids redundant model calls, although the application still uses the computer's resources and local inference may be slow.

The trade-off is real: on my recorded test machine, the first diagnosis took tens of seconds. The payoff is not that every answer is instant; it is that a verified solution can be recalled almost instantly when the same problem returns.

Sentry Agent Tracing

I am entering the Best Use of Sentry Agent Tracing partner category.

StackSoothe implements manual GenAI span tracing conforming to OpenTelemetry and Sentry AI Agent guidelines via a dedicated diagnostic harness (STACKSOOTHE_SENTRY_ENABLED=1). The diagnostic harness includes automated tests that inspect serialized tracing payloads. These tests verify that source snippets, stack traces, model completions, and authorization tokens are not attached to the tested spans or tags.

The regular desktop workflow remains exporter-free by default. These tests validate the specific tracing paths covered by the harness; they are not a blanket guarantee about every possible data flow.

Trace & Span Structure

Each model diagnosis is wrapped in a root GenAI chat span:

  • Operation (op): gen_ai.chat
  • Span Name: chat qwen3:1.7b
  • Span Attributes:
  {
    "gen_ai.operation.name": "chat",
    "gen_ai.provider.name": "ollama",
    "gen_ai.request.model": "qwen3:1.7b",
    "gen_ai.response.model": "qwen3:1.7b",
    "gen_ai.usage.input_tokens": 402,
    "gen_ai.usage.output_tokens": 445,
    "gen_ai.duration_ms": 50800,
    "ollama.timing.load_ms": 3450,
    "ollama.timing.prompt_eval_ms": 4728,
    "ollama.timing.eval_ms": 42576
  }
Enter fullscreen mode Exit fullscreen mode

Waterfall Visualization

[Transaction] stacksoothe-diagnosis (50.8s)
 └─ [Span] gen_ai.chat: chat qwen3:1.7b (50.8s) [status: ok]
     ├─ Model Weights Load:   [████] 3.45s
     ├─ Prompt Evaluation:    [██████] 4.73s
     └─ Token Generation:     [████████████████████████████████████] 42.58s
Enter fullscreen mode Exit fullscreen mode

Strict Privacy Allowlist

To guarantee that private source code and stack traces are never exfiltrated, an automated test (sentry-spike.test.ts) strictly asserts that:

  • errorLog, sourceCode, model completions, and authorization tokens are never attached to span attributes or tags.
  • Span tags are strictly restricted to low-cardinality enums and numeric timings (TIMEOUT, MODEL_UNAVAILABLE, SCHEMA_VALIDATION_FAILED).

Verifiable Artifacts & Test Evidence

  • Trace Manifest: Full JSON dump of 4 diagnostic paths (Success, Network Unavailable, Schema Failure, Timeout) in m3-evidence-manifest.json.
  • Defect Reproducer: Unit test verifying error span tagging and timing retention during schema failures in defect-reproducer.test.ts.

Limitations and next steps

StackSoothe is a prototype, not a replacement for developer judgment. Local model output can be wrong, the initial diagnosis can be slow, and the Fix Notebook is not encrypted at rest. The evaluation is synthetic, and external user testing remains a next step.

The goal is modest: help Flutter developers stop spending time solving the exact same problem from scratch. Diagnose once, verify carefully, and make the next occurrence less work.

Top comments (0)