Skip to content
available for projects000%
All writing
ENTRY-003AI workflow7 August 2026 · 9 min read

SER-01 · SER-01.02 · Building Products with AI

Lessons from working with AI coding agents

The real advantage of AI coding tools is not producing more code. It is shortening the loop between an idea and a verifiable implementation. To do that reliably, you need to design the workflow before you optimize the model.

The first time you work seriously with AI coding tools, the feeling is powerful. You ask for something and files appear, components get written, migrations are prepared and tests are added. In minutes you can produce work that would have taken hours only a few years ago.

Then enough time passes. One agent works in the wrong repository. Another builds a second system because it missed the existing architecture. A fix breaks an unrelated production module. An agent reports completion even though the feature fails on a real device. Another solves a small bug by creating a whole new abstraction layer.

AI made writing code cheaper. It did not make good decisions cheaper.

I use tools such as Claude, Cursor, Codex and Lovable heavily in real product development. Over time the question I care about changed. I used to ask which model writes better code. Now I ask which operating system reduces the space in which an agent can make expensive mistakes.

1. The best model cannot rescue bad context

Imagine telling an agent: fix the Planning screen. You know what that means. The agent does not. Which repository? Which branch? Is Planning /planning or /plan? Which existing architecture must be preserved? Which design reference is canonical? Can it touch the backend? Can it add dependencies?

If those boundaries are missing, most of the implementation is inference. I now think of an agent task as a small contract.

ts
interface AgentTask {  repo: string;  branch: string;  scope: string[];
  preserve: string[];  forbidden: string[];
  acceptanceCriteria: string[];}

Constraining the working surface is more reliable than simply trusting the intelligence of the model. Good context is not a larger prompt. It is the right information plus fewer unnecessary possibilities.

2. Preflight is not optional

I have seen agents produce correct-looking work in the wrong repository or worktree. From the agent’s point of view everything was fine: code written, tests passed, commit created. It was simply the wrong place.

That is why the first step in an engineering task is not writing code. It is verifying the workspace.

bash
pwdgit remote -vgit branch --show-currentgit statusgit log -1 --oneline

These checks are trivial and can save hours. GitHub is the source of truth in my workflow, so the agent must verify the reality it is operating in before it changes anything.

ts
if (!repoVerified || !branchVerified) {  throw new Error("Do not modify code.");}

3. Bad architecture is more dangerous when AI is fast

Unnecessary abstractions used to be expensive to create. You had to design, write and test them. That friction sometimes stopped you. AI can generate the same abstraction in minutes, so the production cost of a bad idea has collapsed.

A small mobile keyboard bug can suddenly produce a new modal shell, viewport provider, hook family and coordination layer. The codebase grows while the original bug may remain unresolved.

Fix the bug, not the universe.

I start with the smallest change that can prove the problem is fixed. A new system is justified only when the current system is actually insufficient. AI speed should shorten validation loops, not automatically expand architecture.

4. “Done” is not a technical state

Agents love to say implementation completed successfully. But successful according to what? Did TypeScript compile? Did tests pass? Did the browser load? Did the production build pass? Was an authenticated flow tested? Did it run on a real Android device? Did production data behave correctly?

Those are different verification levels, so I treat completion as layered evidence.

ts
type VerificationLevel =  | "code_written"  | "typecheck_passed"  | "tests_passed"  | "build_passed"  | "browser_verified"  | "production_verified"  | "real_device_verified";

An agent should report the highest level it actually reached. “Build passed; authenticated browser acceptance could not be verified” is far more useful than “Done.”

5. Tell the agent the boundaries, not only the outcome

A vague instruction such as make the dashboard customizable leaves a huge design surface. The agent may invent resizing, drag-and-drop, arbitrary grids, persistence and new settings. A better task states what must not happen as explicitly as what should happen.

txt
Users may choose which approved cards are visible.
They may NOT:- freely reposition cards- resize cards- create arbitrary dashboard layouts
Preserve the fixed daily hierarchy.

Models are good at filling gaps. If you do not define constraints, they often fill those gaps with more product. More product is not automatically better product.

6. Do not give a huge task to an agent in one breath

A task that combines redesign, performance fixes, mobile work, new views, sync changes and tests may be executable, but the acceptance surface becomes so large that failures are difficult to isolate.

I prefer small, independently verifiable steps.

ts
const plan = [  "STEP 1 — establish canonical data projection",  "STEP 2 — build desktop week shell",  "STEP 3 — implement geometry",  "STEP 4 — mobile behavior",  "STEP 5 — acceptance",];

Each step should be small, testable, reversible and understandable. Use AI speed to reduce cycle time, not to justify a larger scope.

7. Do not blindly hand one agent’s output to another

If one agent implements something and the next receives only “review this,” the second model can inherit the assumptions of the first. It stops behaving like an independent reviewer and becomes another autocomplete layer.

txt
Do not assume the previous implementation is correct.
Inspect:- current code- requirements- changed files- runtime implications
Report mismatches first.Do not modify code yet.

That framing forces the second agent to re-evaluate the problem before defending the existing solution. It is especially useful for large refactors and critical bug fixes.

8. AI agents do not need identical roles

I do not find it useful to collapse every tool into the category AI coder. In practice different tools can play different roles. Their capabilities change quickly, so this is a working model rather than a permanent ranking.

ts
const agents = {  lovable: "rapid product/UI exploration",  cursor: "repo-aware implementation",  claude: "deep reasoning / alternative implementation",  codex: "engineering tasks / audits / implementation",};

The tool I use to explore an interface quickly does not have to be the same one I use for a production repository audit. The goal is not to choose a single favorite. It is to choose a workflow that fits the character of the task.

9. Cheaper code generation made review more valuable

AI makes code generation faster, which means we produce more code. As code volume rises, review becomes more important. The bottleneck moves from typing toward decision, review, integration and validation.

txt
10x coding speed10x product speed
real bottleneck:decision → review → integration → validation

An agent can change twenty files in five minutes. Someone still has to decide whether those twenty files were necessary. Sometimes the most valuable agent task is not “implement this” but “audit this diff and find unnecessary complexity.”

10. Git history matters more in the AI era

Fast agents require easy rollback and understandable history. Small, meaningful commits are therefore more valuable. “feat: improvements” tells the future almost nothing; a specific commit message records the boundary of the decision.

Commit history now serves humans and future agents. A later agent can inspect why a decision was made, where a regression started and which constraints existed at that moment. Git history is becoming a form of long-term project memory.

11. You need a source of truth

When several AI tools touch the same product, multiple realities appear quickly: local, remote, production, an agent worktree and a preview environment. They cannot all be authoritative at once.

ts
const sourceOfTruth = "GitHub";

GitHub is central in my workflow. An agent saying “it works locally” is not the end state. The code has to reach the source of truth and then pass through the correct release path.

12. Production is not development

A change can look perfect locally and fail in production because of stale asset hashes, dynamic imports, service workers or CDN caching. Those failures may not exist at the code level at all.

ts
const done =  localBuildPassed &&  productionDeployed &&  productionRouteLoaded;

For mobile, real-device verification may be another layer. Without explicit production acceptance, “the code is correct” and “the product works” become dangerously easy to confuse.

13. AI should not own the product decision

Ask an agent which option you should choose and it can give a convincing answer. The problem is that it could often argue the opposite option just as convincingly. Models should expand options, analyze risks and implement decisions. Product authority should still remain human.

ts
type DecisionAuthority = {  productVision: "human";  architectureConstraints: "human";  implementationDetails: "human+agent";  repetitiveExecution: "agent";};

When this balance disappears, products converge toward the closest pattern the agent recognizes. A powerful model is not a reason to outsource product vision; it is leverage for shrinking the implementation surface.

14. A prompt is really a temporary specification

The phrase prompt engineering can make the problem sound like finding magic wording. I think of a good coding prompt as a short specification: problem, context, current behavior, desired behavior, things to preserve, forbidden changes and acceptance criteria.

ts
const task = {  problem: "...",  context: "...",  currentBehavior: "...",  desiredBehavior: "...",
  preserve: ["..."],  doNot: ["..."],  acceptance: ["..."],};

That structure is model-independent. I can change the agent tomorrow and the task still makes sense. The durable asset is not the clever prompt. It is the clearly defined work contract.

The simple agent protocol I use today

In simplified form, an engineering task looks like this in my head:

ts
async function runAgentTask() {  await verifyRepository();  await inspectExistingArchitecture();  await restateScope();
  const implementation = await makeMinimalChange();
  await typecheck();  await test();  await build();
  if (browserAvailable) {    await verifyInBrowser();  }
  return {    changedFiles,    verification,    unresolvedIssues,  };}

The most important line is makeMinimalChange(). The natural tendency of an AI system is often to expand. My job is often to narrow.

AI coding did not make technical understanding less important

It is tempting to assume that AI makes technical knowledge less necessary. My experience has been the opposite. Hand-writing every line matters less; understanding architecture, state, network behavior, data models, caching, security, deployment and platform differences matters more.

txt
AI removes typing.It does not remove understanding.

You need to know how the system should work in order to recognize when the agent has built the wrong thing. AI does not eliminate engineering knowledge. It shifts value away from low-level typing and toward high-quality decisions.

The biggest lesson

I do not think the real power of AI coding tools is writing more code. I think it is shortening the loop between an idea and a verifiable implementation.

If you ship three times as many features per day but build the wrong product, you did not become faster. You only moved in the wrong direction faster.

Is this tool improving the quality of my decisions, or only the speed of my output?

Ideally it improves both. But if I have to choose, I still prefer moving slowly in the right direction over moving very quickly in the wrong one. Models will change and tools will change. The operating system around them is the layer that survives those changes.

  • AI
  • Codex
  • Claude
  • Cursor
  • Lovable
  • GitHub
  • Yazılım Geliştirme

SER-01 · SER-01.02

Building Products with AI

From vibe coding and agent orchestration to production Lovable workflows and real AI integration: keeping product and architecture control while moving faster.

AVAILABLE FOR PROJECTS · PRODUCT & SYSTEMS ARCHITECT · TAKEOVER / STABILIZE / OPERATE · WEB · ANDROID · WINDOWS · AHMET CANAL

Contact

Has your product grown faster than its system?

Send the current situation, your biggest blocker and the outcome you want. We will clarify scope together.

Availability

Open to new consulting and project-based work.