Published:
This was not a generated demo or a greenfield toy app. Chat-O is an existing Elixir and Phoenix LiveView product with background jobs, streamed responses, image storage, and years of application state. DeepSeek worked in that codebase through OpenCode.
The product result is covered in The Image Studio: See Every Version and Edit the Right One. This post is the engineering story behind its next phase.
The first request was deliberately broad:
That crosses more boundaries than the interface suggests. The browser has to capture shapes. LiveView has to validate their data and preserve modal state. The server has to render those marks onto an image. A background job has to produce the edit. The gallery has to recognize the correct result, and the relationship between source and edit has to survive a reload.
The actual feature running in Chat-O: choose the circle tool, mark the target area, and describe the change without leaving the studio.
DeepSeek did not stop at a mockup. It connected the full path.
It added an annotation hook with rectangle, circle, and freehand tools. It made shapes selectable, movable, resizable, and deletable after we said the first interaction felt too rigid. It rendered the marks server-side, attached the annotated source to the edit request, and kept the studio in a generating state while the background job ran.
It also built the state around the image itself: gallery navigation, Before/After comparison, and the link between an edited image and its source. When we asked whether that comparison could still work after leaving and returning later, the model added persisted image ancestry rather than treating Before/After as temporary browser state.
One of its best decisions came during testing. It extracted the viewer transitions into a small, pure state module. That made navigation, pending states, shape limits, comparison mode, and result selection much easier to exercise without booting the entire LiveView for every case.
The final change was substantial:
| Area | What changed |
|---|---|
| Browser interaction | Drawing, selecting, moving, resizing, and deleting annotations |
| LiveView | Modal editing, pending/error states, gallery refresh, and Before/After controls |
| Image processing | Server-side rendering of visual instructions onto the source image |
| Persistence | Source-image ancestry retained for later comparisons |
| Tests | Focused coverage for rendering, viewer state, LiveView events, and UI output |
All of the focused tests we ran for this work passed.
The first pull request was only the beginning. The work went through seven major passes: the initial feature, browser debugging, movable drawing objects, broader automated coverage, persistent Before/After history, independent review, and a final review-hardening pass. DeepSeek reached a working feature quickly, then kept improving it as product feedback and review raised the bar.
Before/After is part of the real viewer state, not a presentation mockup. The relationship survives after the edit is complete and the studio is reopened.
The most useful part of the session was watching the model debug its own work.
During a browser run, an edit really did submit and produce a new image, but the expected pending state did not appear correctly. DeepSeek followed the failure into the server logs and found a LiveView crash caused by an unloaded Ecto association reaching the message renderer. It fixed the render path and tried the workflow again.
That is a better signal than code generation alone. The model was able to move between browser behavior, logs, Elixir state, and the rendered component instead of declaring success when the backend happened to create an image.
The interaction design also needed iteration. The first drawing tools could mark an area, but the shapes were not pleasant to adjust. We asked for movable objects. DeepSeek returned to the JavaScript hook and added selection, movement, resizing, deletion, and clearer visual handles.
Then we asked for stronger tests. The model added renderer tests and LiveView coverage, extracted the viewer state, and covered the important transitions. Only after that did we ask for durable Before/After history, which required a database field and a migration to record the source image for each edit.
The feature worked in the browser, and the focused suite passed, but review still found important edges.
The original completion logic could confuse an unrelated gallery image with the result of an edit. A failed image job could leave the modal stuck on “Generating.” Client-supplied freehand data needed stricter bounds. Temporary files were not guaranteed to be cleaned up after every failure. The gallery was also doing more work than necessary while streamed chunks arrived.
Those are exactly the kinds of problems a polished happy path can hide. The review was human-led and human-approved, with OpenAI Codex using GPT-5.6 Sol helping with most of the systematic code review. We sent those findings back to DeepSeek, which tightened result identity, failure recovery, shape validation, cleanup, and gallery refresh behavior. It also added regression coverage around the state transitions.
Not every concern disappeared. Some image preparation still does synchronous work inside the LiveView, and the JavaScript interaction layer would benefit from its own automated browser-level test harness. The pull request should be judged on those remaining tradeoffs, not on how impressive the demo looks.
DeepSeek V4.1 Flash was surprisingly strong at sustained, cross-layer implementation. It navigated an unfamiliar codebase, changed Elixir and JavaScript, used browser feedback, diagnosed a framework crash, wrote tests, handled a schema change, and responded constructively to a human-led review assisted by Codex.
It was not a one-prompt success. Product feedback changed the interaction. Testing exposed a crash. Review found failure and concurrency cases that the first pass missed. The useful result came from the loop:
That is how we want to use coding agents at Chat-O. The model can do a surprising amount of the work, but “it built the feature” does not mean “skip review.” In this case, DeepSeek V4.1 Flash built the feature and also did much of the hardening after review. Both parts matter.
We first tested the same model on a dependency upgrade; you can read that DeepSeek V4.1 Flash benchmark here.