Engineering Notes

My AI Programming Workbench: Orchestrating Models Instead of Hunting for One Best Tool

How I combine Ollama with Qwen3.5:9B, OpenCode, Claude Code, Codex, and desktop GPT through project context, architecture review, task decomposition, cross-review, and evidence-based quality gates.

My programming toolbox is no longer a single product.

Locally, I run Ollama with Qwen3.5:9B. In the terminal I use OpenCode, Claude Code, and Codex, and I also route Kimi K3 through OpenCode. For complex desktop work, I use the desktop version of GPT. These tools differ in capability, cost, privacy, and interaction style, but I have become convinced that output quality depends less on finding one “best model” than on organizing several models well.

I do not want one agent to receive an ambiguous request and independently design, implement, and approve the result. My workflow resembles a small engineering team. I establish shared project context, ask a strong model to develop an architecture, and personally review the critical decisions. I then divide the work into bounded tasks, assign them to different tools, ask other tools to review the implementation, and close the loop with tests, type checks, static analysis, and observed behavior.

The point is not to open more terminals. It is to build an auditable delivery pipeline:

Requirements and constraints
          ↓
Project context (AGENTS.md / CLAUDE.md / documentation)
          ↓
Design (architecture, domain boundaries, risks, acceptance criteria)
          ↓
Human review and decision
          ↓
Task decomposition → execution → independent cross-review
          ↓
Automated checks + scenario validation
          ↓
Corrections become durable project context

A layered workbench, not a list of tools

Different models belong at different points in the workflow. Sending every task to the most expensive model wastes resources. Giving a high-risk design decision to a small local model can make the team move quickly in the wrong direction.

LayerTools I useBest suited to
Local explorationOllama + Qwen3.5:9BCode explanation, local search, drafts, low-risk edits, and assistance with sensitive context
Open orchestrationOpenCode + Qwen / Kimi K3Model switching, experiments, cost-capability comparisons, and replaceable terminal workflows
Deep designClaude CodeBroad repository comprehension, architecture proposals, domain modeling, and migration planning
Engineering executionCodex / Claude Code / OpenCodeRepository exploration, implementation, refactoring, testing, repair, and review
Desktop collaborationDesktop GPTCross-file and visual reasoning, research synthesis, long-running collaboration, and editorial refinement

This is not a permanent ranking. Models and products will change. The stable rule is to route work according to risk, context size, verifiability, cost, and privacy requirements.

Low-risk, reversible tasks should usually start with a local or lower-cost model. Cross-module reasoning deserves a stronger model. Architecture, data migration, security, and production changes require a human decision. No model output substitutes for acceptance evidence.

Start with project context, not a clever prompt

When I initialize a project, I create project-level instructions such as AGENTS.md and CLAUDE.md. They describe the stack, repository structure, operating commands, architecture, and engineering constraints. This preparation looks like documentation, but it establishes the ceiling for every agent that follows.

Without shared context, every tool rescans the repository, guesses conventions, and may invent a different implementation style. Useful project context should answer:

Purpose: the problem, users, and current stage
Stack: languages, frameworks, versions, and major dependencies
Architecture: module responsibilities, dependency direction, hard boundaries
Domain language: core concepts, terms, and invariants
Commands: install, start, test, type-check, and build
Conventions: naming, errors, logging, tests, and commits
Safety: sensitive data, secrets, external calls, and prohibited actions
Definition of done: mandatory quality gates for every change

Context files should not become thousand-line dumping grounds. AGENTS.md is a good home for stable, executable, cross-tool rules. CLAUDE.md can contain Claude-specific interaction guidance. Detailed architecture belongs in focused documents linked from the entry point. Rules should be concise, testable, and updated with the code.

One principle matters greatly: do not duplicate the same rule across several files. Duplication eventually becomes contradiction. Shared facts need one canonical source; tool-specific files should contain only the differences.

Let a strong model design, but keep architecture accountable to people

For medium and large changes, I often ask Claude to propose the architecture, domain boundaries, DDD model, and implementation path. AI is excellent at expanding the problem space quickly: identifying affected modules, proposing alternatives, finding failure paths, exposing hidden dependencies, and turning vague requirements into a structure that can be debated.

A polished design document is not automatically a correct design. I review five things:

  1. Does it solve the real problem? Or has it added complexity to display architectural sophistication?
  2. Are the boundaries natural? Do they follow business change, or merely apply DDD vocabulary?
  3. Are dependencies controlled? Are data flow, transactions, recovery, and compatibility explicit?
  4. Can it ship incrementally? Or does it require a high-risk big-bang rewrite?
  5. How will we know it works? Are test, performance, migration, and business acceptance criteria defined before implementation?

DDD is a way to organize complex business knowledge, not a decorative default. A short-lived module with straightforward CRUD does not need aggregates, repositories, and extra layers for their own sake. DDD earns its cost when rules are complex, language is contested, and boundaries must evolve over time.

I therefore ask the model to explain why the design fits, what alternatives exist, and when the recommendation should not be used. Good architecture is not an impressive diagram. It is a set of decisions that can be challenged, traded off, and verified.

Decompose work around boundaries and evidence

Once the design passes review, I do not send another agent a one-line request to “implement the whole feature.” I create task packets that are independently understandable and verifiable, with as little overlapping write scope as possible.

A useful task packet includes:

Objective: the user or system behavior that must change
Scope: permitted modules and explicit non-goals
Context: relevant decisions, interfaces, and conventions
Acceptance: tests, examples, performance, or observable behavior
Risk: compatibility, data, security, and rollback requirements
Delivery: code, tests, documentation, and unresolved questions

Tasks should be split by domain boundary, module, read/write responsibility, or verification concern—not mechanically by file. When multiple agents edit the same central file, time saved in generation is often lost to conflict resolution and context synchronization. Parallelism pays only when boundaries are clear and write scopes barely overlap.

I also control how much context each task receives. Giving an agent the entire repository is not always helpful. Irrelevant information dilutes constraints and increases accidental associations. Stable project rules should be shared, while each task receives only the local context necessary for its objective.

Cross-review: different tools should search for different failures

I ask other tools to cross-review the implementation. The value is not that two models can vote. It is that an independent reviewer can challenge the implementer's assumptions.

An effective review is more specific than “look over this code.” I ask reviewers to check:

The reviewer should provide evidence: a file and location, trigger condition, impact, reproduction path, and suggested correction. The implementation tool can then address the finding and rerun validation. When models disagree, I do not decide by brand. I return to requirements, code, tests, and reproducible facts.

There is also a danger of agents endorsing one another. If several tools inherit the same faulty assumption, they can confidently agree on the wrong result. Independent verification should change either the information source or the validation method: one model performs static review, another runs tests and scenarios, and a person reviews the critical business judgment.

The final judge is a quality gate, not a model

Code that looks plausible is not evidence that the system behaves correctly. My validation ladder usually looks like this:

Formatting / linting
        ↓
Type checking / compilation
        ↓
Unit and integration tests
        ↓
Critical user journey or API scenario checks
        ↓
Diff and architecture consistency review

Automatable checks belong in project commands and CI, not in an agent's memory. An agent must report which commands it actually ran, their results, and which checks could not run because of environmental limits. An unexecuted test is not “probably passing,” and a prediction is not evidence.

High-risk actions need separate governance. Production deployment, database migration, destructive changes, permission updates, and external communication require explicit approval and a recovery plan. Local inference can improve privacy, but it is not automatically secure. Model provenance, tool permissions, secrets in prompts, logs, and external plugins still require control.

Turn every correction into default capability

The lasting value of this workflow is not that one change ships faster. It is the learning loop.

When review exposes a recurring problem, I decide which layer should absorb it. Stable engineering constraints go into AGENTS.md. Architectural trade-offs become ADRs. Domain facts enter domain documentation. Mechanical errors become lint rules or tests. High-value failures become regression cases. The next task should not depend on me remembering the same warning again.

I can then track cycle time from request to merge, first-pass validation rate, review findings, human rework, rollback count, and the cost of comparable tasks across models. Generation speed alone is a poor evaluation metric. A fast model that creates hours of review work may be the slower system.

My conclusion: the developer becomes the designer of the work system

Ollama, Qwen, OpenCode, Kimi, Claude Code, Codex, and desktop GPT will all continue to evolve. Today's strongest model may become an ordinary component tomorrow.

What compounds is model-independent: clarifying the objective, encoding context in the project, turning architecture into reviewable decisions, decomposing work into verifiable units, assigning execution and review independently, and closing the loop with automated evidence.

AI lowers the cost of coding and exploration, but it does not take ownership of judgment or responsibility. My role is no longer limited to typing every line. It is to design an engineering system in which the right context enters, different capabilities cooperate, errors surface early, and experience becomes durable memory.

That may be the deepest change AI programming brings: we are no longer only designing software; we are also designing the way software gets produced.

Back to Engineering Notes