Case study
- Desktop
- Mobile
- AI tools
Building the AI agent workflow we wanted to use
Crystal Lattice was planned as a public product, but its first milestone was practical: create an MVP we could use for real development, inspect while it worked, continue after failures, configure for different providers and extend without scattering every new capability through the core application.
- Project
- crystallattice.dev
- First milestone
- MVP used for internal development
- Current status
- In active development
Starting problem
OpenCode was the closest existing product to what we wanted, but several practical problems remained.
Cost tracking was unreliable even though the provider already made the necessary information available. If a provider request failed, continuing from the point of failure was not possible. We had to undo the turn—which also reverted its completed tool calls—and start the work again.
In the required OpenRouter integration, reasoning data was lost after tool calls, so the model had to reason through the work repeatedly. Correcting this provider-specific problem was taking disproportionate time because the complete solution required changes and upstream pull requests across several repositories.
Tool descriptions also contained instructions we did not want and could not configure. Changing a provider option such as reasoning effort meant returning to configuration rather than adjusting it in the interface.
Codex and Claude Code were deliberately more user-friendly. For our use case, that also meant abstracting details we wanted to see and controls we wanted to reach.
At the same time, providers were introducing native capabilities such as web search and compaction, while the available open-source agents offered no simple way to add them. We did not want to maintain more workarounds and corrections scattered across several repositories. We wanted a product whose underlying behavior could be understood, adjusted and extended.
What the first MVP needed to make possible
- Visible
- Provider cost, reasoning, tool activity and request state needed to remain understandable while work was happening instead of being hidden behind a simplified interface.
- Configurable and customizable
- Provider parameters, reasoning effort, tool instructions and relevant interface controls needed to be changeable without scattering special cases through configuration files, UI components and core behavior.
- Replaceable and extensible
- Providers, tools, reporting and provider-native features needed coherent boundaries so they could be added or replaced without rewriting the product.
First milestone: a working terminal and Codex-like tools
The first useful milestone was a simple working terminal.
The MVP needed only a small Codex-like tool set: Bash, apply_patch and web search. This combination was enough to work naturally with the agent and continue developing the application.
The exact editing tool mattered. With less suitable edit tools, the model could spend a long time reasoning about how to perform the edit or why the tool had failed. apply_patch gave the workflow the same kind of direct, predictable editing interaction that made Codex effective for this use case.
The MVP preserved the working state after completed steps, so a provider failure could be continued without undoing the tool calls that had already finished. Sessions could also be forked from an arbitrary place in the conversation, rather than only after a user message.
The usage plugin captured the provider's native usage information and exposed the cost of the request together with the running session total. The provider already supplied the raw values; the plugin contained the provider-specific interpretation needed to make them visible in the interface.
Why the original provider response remains the source of truth
When a provider expects data from an earlier response to be sent back with the next request, keeping that data in its original form is the simplest approach. Converting it into a common format and reconstructing the provider-specific version for every request adds complexity and creates a risk of information loss.
Crystal Lattice retained the complete provider-native history in native_messages and reused it as the input for subsequent requests. A separate normalized messages representation supported display and generic session operations.
Reasoning was an important test case because its format and continuation requirements varied by provider. The data to preserve could include reasoning text, encrypted reasoning data and signatures. Retaining the original response made these differences easier to manage across tool-call rounds while keeping the data needed for continuation intact.
Preserved provider data
- Encrypted or native reasoning
- Provider-specific tool calls and IDs
- Usage and cost data
- Cached-token metadata
- Citations
Later integrations
- Native compaction items
- Attachments and images
- Other continuation data
Plugin-driven behavior and controls
Provider-specific cost handling, reasoning controls, tools and interface options were implemented as plugins instead of being scattered through the core and frontends.
This meant a provider-native capability such as web search or compaction could be introduced as a coherent extension. A parameter such as reasoning effort could be made available in the interface through provider-aware plugin data instead of being hardcoded into each frontend.
- Provider behavior could be replaced or extended.
- Tool instructions and capabilities could remain configurable.
- Interface controls could follow the active provider or feature.
- Reporting could contain the provider-specific logic it needed.
Mobile access to the computer
The mobile application acted as a chat interface for the agent running on the computer.
On the same network, the phone could connect directly over the local network. Away from that network, the bridge provided the connection. The phone provided another interface to the same agent and sessions running on the computer.
Current product work
These current views show capabilities added or expanded after the first MVP.





How the MVP was proven
Once the basic terminal worked, we started using Crystal Lattice for real development immediately—including the continued development of Crystal Lattice itself.
That use was the practical proof for the first milestone. The product did not remain a prototype waiting for a later test project: it became the tool used to continue building the product.
The initial MVP became useful for the workflow that had motivated it.
Current status and next milestone
Crystal Lattice was planned for public use from the beginning. The first MVP was used internally because that gave the product real work to solve from the moment the terminal became usable.
The project remains in active development. The next milestone is a public open-source release, beginning with a stronger first experience for macOS users and then expanding support and first-use quality across other operating systems.
Developing an AI product or agent workflow of your own?
Tell us which workflow needs to remain visible, which behavior must be configurable, and which providers, tools or features need room to evolve.
Discuss your product

