In our July Quito Lambda session, Stack Builders Senior Software Developer Cristhian Motoche explores a practical question: how can teams make an AI application run consistently across different developers’ machines? Through a working Python mystery game, he demonstrates how devenv can describe packages, services, scripts, hooks, and environment behavior in code. Watch the full Quito Lambda presentation on YouTube.
AI prototypes often begin with a model and a prompt. Production-minded engineering has to account for much more. Developers may need a particular Python version, a local model server, several packages, environment variables, startup commands, quality checks, a database, and a predictable way to run everything together.
If those requirements live only in setup notes or in one developer’s memory, the application may work on one machine and fail on another. In this Quito Lambda talk, Cristhian showed how reproducible development environments can reduce that gap. The session used devenv, which builds on Nix, to declare the local environment for an AI application and keep the setup alongside the project’s code.
The talk did not present devenv as a universal answer. Instead, it offered a concrete demonstration of what the tool can manage, where it can make development easier, and what teams still need to evaluate before adopting it.
Why the development environment belongs to the project
One of the first problems developers encounter on a new project is familiar: the application works on one computer but not on another. Cristhian identified several possible causes, including different language versions, operating-system libraries, services, environment variables, and setup steps.
The cost is not limited to an inconvenient first day. When an environment cannot be reproduced, a new team member may need another developer’s help before productive work can begin. The project then depends on knowledge that is difficult to review, test, or keep current.
Written setup instructions can help, but they can drift from the actual application. Version managers improve consistency for a language or toolchain, but they do not necessarily define the services, scripts, secrets, hooks, and lifecycle steps a complete application requires. Development containers can package a broader environment, but they introduce their own container tooling and configuration.
The principle behind devenv is to treat the environment as code. A project can declare what it needs in a version-controlled file, allowing the team to review environment changes in the same way it reviews application changes. This aligns closely with the broader goal of reproducible engineering described in our article on self-contained Nix scripts.
How devenv builds on Nix
devenv uses Nix underneath. In Cristhian’s explanation, Nix manages packages in the Nix store, where binaries and libraries are stored using hashed paths. Packages that have already been built can be retrieved from a shared cache, which helps avoid rebuilding the same dependencies for every environment.
A team could work directly with Nix shells, but that requires more familiarity with the Nix language and its syntax. devenv provides a higher-level way to declare common development-environment needs, while retaining Nix’s reproducibility and package management.
Cristhian described the configuration as a function: it receives inputs, defines what should exist in the environment, and produces a configured development shell. Rather than documenting a sequence of manual installation commands, the file expresses the desired result.
The talk’s first example declared the project’s packages, Python tooling, environment variables, common scripts, and local AI dependencies. Entering the project directory could automatically activate the environment when a devenv configuration was detected. The shell could also display project information or run initialization behavior, giving the environment a defined lifecycle.
For another example of the same approach, our team has written about combining devenv with nixpkgs-terraform to manage Terraform versions and development checks.
Building the AI demo in three stages
Cristhian organized the demonstration around a Clue-style mystery game. The application used images representing ten characters, ten objects, and ten locations. A vision model first described what appeared in each image. The application then selected one item from each category, and a language model generated a mystery story with clues. The player had to identify the person, object, and location.
The first stage focused on image analysis. The environment included Ollama, which served an open model locally through HTTP, and LLaVA, a vision model that could process an image and respond to a prompt. Cristhian showed the model an image of a kitchen and reviewed the generated description. It correctly recognized the setting and several visible materials, although the description was not perfect.
This was an important part of the demonstration. Open models can make experimentation accessible, but their output quality depends on their capabilities and the computing resources available. Cristhian ran the demo without a dedicated GPU and noted that vision models are relatively large. Local inference therefore took time, even though it remained practical for the example.
The second stage assembled the game in Python. Streamlit provided a straightforward interface for the prototype, while the local model generated the mystery narrative. Cristhian explained that a language model was useful here because manually programming enough rules to produce varied stories would require considerable work and could still become repetitive.
The generated clues were imperfect. During the live game, the audience did not correctly identify the solution, and Cristhian noted that the smaller open model did not produce the best hints. That result strengthened the technical lesson: a reproducible environment makes an experiment repeatable, but it does not guarantee that the selected model, prompt, or output will meet the application’s needs.
The final stage replaced the local text model with a cloud model accessed through Google AI Studio. The application structure remained largely the same, but the generated clues were clearer. Even then, the audience only guessed one part of the solution correctly, and Cristhian suggested that the prompt still needed adjustment.
The comparison showed why AI engineering requires iteration. Model selection, prompt design, latency, local compute, and provider limits all affect behavior. The value of a declared environment is that the surrounding application setup stays controlled while those variables are tested. Teams exploring similar product questions can also read our strategic framework for integrating AI into products, which emphasizes moving from demonstrations toward purposeful implementation.
What the environment configuration managed
Across the examples, devenv coordinated more than a Python version.
Packages: The configuration declared tools such as Python, Ollama, and OpenCode for the project. Cristhian noted that devenv exposes a large package catalog through Nix, including tools for different languages and mobile development.
Scripts: Common operations were given short project commands. Instead of asking every developer to remember a long command, the project could define actions such as analyzing images, starting Ollama, or running the game.
Languages and dependencies: A later example enabled Python more directly, created a virtual environment, and used uv to manage Python packages. The configuration could also specify a package file so dependencies were installed when the environment initialized.
Services and processes: Ollama ran as a service, and the application itself could also be declared as a process. In the final example, the game started on port 8080 and ran alongside its supporting services. Cristhian also demonstrated PostgreSQL as a project service.
Environment variables and secrets: Variables could be defined in the environment. The talk briefly showed a service using a secret reference, but time did not allow a full explanation of secret management.
Lifecycle behavior: The environment supported commands that ran when entering the shell and at other points in the setup process. This made it possible to prepare an application before development began.
Git hooks and tests: Cristhian intentionally damaged the formatting of a Python file, staged it, and attempted a commit. A hook ran Black, rejected the inconsistent formatting, and corrected the file. The hook was already part of the environment, so it did not require a separate initialization step.
Dynamic ports: When Cristhian started the same services in another Git worktree, devenv selected a different port because the default was already occupied. This can be useful when a developer or coding assistant works on multiple branches or features concurrently. Each environment can run without requiring the developer to manually assign every port.
These features connect reproducibility with day-to-day delivery. The goal is not simply to install the right interpreter. It is to give contributors a consistent route from opening the project to running, testing, and changing it. That same attention to repeatable tooling is relevant to reliable releases and scalable infrastructure, which are core concerns in DevOps and scalability work.
What the live demo revealed about local and cloud models
The session did not frame local and cloud models as interchangeable. The local setup provided direct access to an open model and kept the demo runnable on Cristhian’s machine, but it came with model size, speed, and output-quality constraints. The cloud model had access to more resources and produced more specific clues, but it required an account, an API key, and acceptance of provider rate limits.
For a proof of concept, either route may be useful depending on the question being tested. A local model can help a team explore an idea without immediately committing to a paid service. A hosted model can make it easier to test stronger model behavior without provisioning equivalent local hardware. The surrounding engineering decisions still matter in both cases.
The demo also included OpenCode, an open coding assistant with a command-line interface and a free model option. Cristhian used it to ask what the project did, and the assistant summarized the codebase without requiring him to inspect every folder manually. He also emphasized that free access had limits. The takeaway was not that one tool should replace engineering review, but that accessible tools can help developers begin experimenting.
Tradeoffs teams should evaluate
Cristhian closed with clear limitations. Nix stores separate hashed package paths, so multiple environments and large AI models can consume significant disk space. Advanced customization still requires familiarity with Nix syntax. Cross-platform behavior is not automatic in every case, and some packages or configuration may require operating-system-specific conditions.
The question-and-answer session provided a practical adoption example. An attendee described maintaining two Angular applications that required different dependency versions and currently used separate virtual machines. Cristhian explained that devenv could define a different Node version and environment for each project, provided the required packages were available. This could avoid using a full virtual machine solely to separate those toolchains.
That example captures the decision well. devenv may be valuable when environment differences are already creating friction, when several services and tools must be coordinated, or when teams need parallel and reproducible setups. For a very small project, a version manager may be enough. The right choice depends on the complexity the team is actually managing.
Reproducibility makes experimentation easier to share
The mystery game was playful, but the engineering problem was serious. An AI application is not only its model call. It is also the language runtime, dependencies, services, environment variables, scripts, quality checks, ports, and workflow that allow a team to run and improve it.
By declaring those elements in code, developers can reduce hidden setup knowledge and give every contributor a more consistent starting point. They can also change models, prompts, and providers without rebuilding the entire local workflow from memory.
For teams moving from AI experimentation toward a maintainable application, reproducibility is part of delivery quality. It creates a stable base for testing ideas, comparing results, onboarding contributors, and deciding what belongs in production.
If your team is evaluating an AI-enabled product or needs a more reliable development and deployment foundation, explore Stack Builders’ web application development and enterprise DevOps consulting services, or contact our team to discuss the right next step.