TL;DR: There are two ways to work with an AI coding assistant. If you know exactly what needs to happen, delegate it with a clear spec and walk away. If you're still figuring the problem out, leverage the AI as your pair and stay in the loop. Cap delegated work at two review loops, then switch modes. A Jest-to-Vitest migration taught me most of this the hard way.
How AI Changed My Coding Workflow
Special thanks to my teammate Minh Le at Lorikeet, whose insights on AI-assisted development workflows have been invaluable to my learning of this topic.
When AI coding tools first came out, I treated them as fancy autocomplete. Then agents arrived that could implement entire features unattended, and I learned quickly, after watching several AI-generated PRs turn into messes, that power without a working method mostly produces messes faster. The breakthrough for me was realizing there are really just two ways to work with AI: delegate something and walk away, or leverage AI as your pair programming partner. Knowing which one fits the task is the whole game.
The Coding Task Spectrum
Think of any coding task on a spectrum. On one end are tasks where you know exactly what needs to happen: "remove this feature flag," "add unit tests for this service." On the other end are tasks where you're still figuring things out: "why is this page slow?", "how should we architect this feature?" Where your task falls tells you how to work with AI.
Task Knowledge Spectrum
Known Tasks (Delegate)
- • Removing feature flags
- • Adding unit tests
- • Fixing diagnosed bugs
- • Implementing specs
Unknown Tasks (Leverage)
- • Diagnosing race conditions
- • Architectural design
- • New feature discovery
- • Performance optimization
A quick test: delegate only when you know exactly what needs to be done, can point at examples, and can define success. If the problem still needs diagnosis, exploration, or an architectural decision, that's a leveraging session.
Workflow #1: Delegating (Assign and Forget)
Delegation is simple: write up what needs to happen, hand it to an AI agent, and go work on something else. Come back later, review, ship. The catch is that you need to know exactly what you want. If your spec says "figure out the best way to do this," you're not delegating. You're hoping the AI makes good architectural decisions for you, and it won't.
The Delegation Protocol
My flow is nothing fancy, but keeping the steps explicit stops me from cutting corners on the spec:
1. Write a Clear Specification ├─ State the exact outcome ├─ Provide code references ├─ Include examples └─ Define success criteria 2. Create the Task/Issue ├─ Use your team's tracking system ├─ Include all relevant context └─ Link related files/discussions 3. Assign to AI Agent ├─ Match task complexity to agent capability ├─ Provide access to relevant codebase └─ Set clear boundaries 4. Batch Review Later ├─ Limit to 1-2 review loops max ├─ Accept or reject (no endless iterations) └─ If unclear, handle manually
Writing Effective Delegation Specs
The quality of the specification decides the outcome. Compare these two versions of the same task:
Poor Spec
Task: Add dark mode support Please add dark mode to the app.
Too vague: no context, no examples, no constraints.
Good Spec
Task: Add dark mode toggle to Settings page Reference: See ThemeContext.tsx for theme state Location: Add toggle to SettingsPage.tsx:67 (below notification preferences) Behavior: - Toggle should use Switch component from ui/Switch - Persist preference to localStorage - Apply theme immediately on change Tests: Add test verifying localStorage update
Specific and actionable, with clear constraints and examples.
The One-to-Two Review Loop Rule
Here's a rule that's saved me so much time: if the AI doesn't get it right after one round of feedback, do it yourself. I used to go back and forth with agents trying to get them to understand what I wanted. After round two, you're just wasting time. Either your spec was unclear (fix it for next time) or the task was too complex for delegation and should have been a leveraging session. Reject the PR and switch modes.
Real Example: Jest to Vitest Migration
This one burned me. We had a straightforward-sounding task: migrate our test suite from Jest to Vitest. Clear input, clear output, well-documented migration path. Textbook delegation, right?
I wrote up a solid spec: swap the test runner, update the config, replace Jest globals with Vitest equivalents, make sure everything passes. Handed it to a Cursor agent and went to work on something else.
First pass came back and it looked reasonable. The syntax migration was clean: jest.fn() became vi.fn(), jest.mock() became vi.mock(), imports were updated. But then Buildkite went red.
The problem wasn't the test syntax. It was the config. Vitest handles module resolution differently than Jest, and our monorepo setup with custom path aliases needed specific resolver config that the agent didn't understand. It also missed that some of our Jest config was split across jest.config.ts, jest.setup.ts, and CI-specific overrides in the Buildkite pipeline.
I gave it one round of feedback pointing at the failing CI logs and the config files it missed. Second attempt still broke, this time because of how Vitest handles CSS module mocks differently. That's when I applied the rule: two loops, done. Time to switch modes.
I pulled it into a leveraging session instead. With the AI as my pair, I walked through each Buildkite failure, traced the config differences, and we figured out the resolver and mock setup together. What the agent couldn't see autonomously, like how our CI environment had different module resolution than local dev, we diagnosed interactively in about 30 minutes.
The Takeaway:
The syntax migration was a perfect delegation task. But the config and CI integration? That was a leveraging task hiding inside a delegation task. The 1-2 loop rule caught it early. Without it, I would've spent hours going back and forth on config tweaks through an agent that couldn't see the full picture. Instead, I switched workflows and shipped it.
Workflow #2: Leveraging (Active Collaboration)
Leveraging is completely different. You sit down with the AI and work through a problem together: steering, correcting, exploring options. It's pair programming, except your pair can read your entire codebase instantly. It requires your full attention, which is exactly why it's the right mode for diagnosis, design, and anything you can't yet specify.
The Critical Skill: Interrupting Effectively
The most important thing I can tell you about leveraging: interrupt early and often. When the AI starts heading in the wrong direction, don't wait for it to finish. Mistakes compound. Every line built on a flawed assumption makes the problem worse. I've seen people let agents write 500 lines in the wrong direction because they didn't want to interrupt. Stop it the moment you see a wrong pattern, a bad assumption about your data, missing error handling, or a security risk.
Providing Context: The Make-or-Break Factor
The other separator is precision. Don't say "update the API service" when there are five API services in your codebase. Give file paths, line numbers, function names.
Vague Context ❌
"Update the API call service to handle retries better."
Agent searches entire codebase, possibly finds wrong service.
Precise Context ✓
"In src/services/api/subscriber.service.ts:87-120, add exponential backoff to the fetchSubscriberData method."
Agent knows exactly where to look and what to modify.
Common Leveraging Patterns
Pattern 1: Read and Propose
Start by having the AI explore the codebase and propose multiple approaches before committing to implementation.
You: "Read src/auth/* and propose three approaches for adding
OAuth2 support. Consider our existing session management."
AI: [Explores codebase, identifies patterns]
"I've analyzed the auth layer. Here are three approaches:
1. Extend SessionManager with OAuth adapter
Pros: Minimal changes, reuses existing logic
Cons: Couples OAuth to session lifetime
2. Separate OAuthProvider service
Pros: Clean separation, easier testing
Cons: Duplicate token refresh logic
3. Unified TokenManager abstraction
Pros: Handles both session and OAuth cleanly
Cons: Requires refactoring existing code"
You: "Let's go with option 3. Start with the TokenManager interface."Pattern 2: Incremental Review Notes
As you collaborate, keep a running list of minor issues to address after the main work is complete. This prevents context-switching and maintains momentum. Other patterns I reach for: rapid throwaway prototypes to surface missed requirements, and giving the AI one or two example tests so it replicates your mocking and assertion style instead of inventing its own.
You: "The main logic looks good. I'm noting these for cleanup:
- Add JSDoc to public methods
- Extract magic number to constant
- Handle edge case for empty arrays
Continue with the error handling implementation.
We'll fix these notes after."Watch out: Don't try to juggle multiple leveraging sessions.
I've tried running two active AI collaboration sessions side-by-side. It doesn't work. You lose the mental model of each task, mistakes compound because you're not catching them early, and the output quality drops because you're not steering either session properly. If a task needs your full attention, give it your full attention. If it doesn't, it's a delegation task, not a leveraging task.
You Own the Output, Always
Every line of AI-generated code is your responsibility. Not the AI's. When it breaks in production or ships a security hole, that's on you. Review everything, understand the architectural decisions, and remember that passing tests validate behavior, not correctness or maintainability. You still need to read the code.
Wrapping Up
The delegate vs leverage framework is the system I keep coming back to. Is the task well-defined? Delegate it with a real spec and a two-loop limit. Is it exploratory or complex? Leverage AI as your pair and interrupt early.
Start with something easy. Pick a feature flag removal, write a good spec, delegate it, and see what happens. Then try a leveraging session on something harder, like a performance investigation. The intuition for which mode fits which task builds fast, and it's the most useful AI skill I've picked up.
