I’ve been using AI coding tools every day for several months, and they’ve become part of how I plan work, investigate unfamiliar code, implement features, debug problems, and think through tests. Most days, they make me faster. Small tasks that once took an hour may take fifteen minutes, and I can get oriented in an unfamiliar framework without spending half a day jumping between documentation, search results, and source files. AI is also good at suggesting test cases I might not have considered on my own.
I’ve lost time to it too, usually because the agent made an assumption I didn’t notice. For example, a simple implementation goes in the wrong direction. When I call it out, the agent sometimes starts chasing the problem with more patches. Before long, a change that should have involved two files is touching six, and I’m reviewing a solution to the wrong problem. At that point, I stop the work, go back to the requirement, and figure out why the scope is growing. The speed is valuable, but only when I can still understand and control the work.
Where the time savings are real
AI works especially well for me when the task is narrow and I can check the result myself. Small, one-off changes are the obvious example. The agent can handle a routine implementation, update a test, or trace an existing code path with pretty good results.
I’ve also found it useful when I’m working with a language, framework, or codebase that I don’t use every day. I can ask specific questions, follow the answers into the relevant files, and build up enough knowledge to start contributing. The same is true for testing, where an agent will often suggest cases I missed.
I start larger projects on my own
For a larger project, my first step is to write out the plan myself. This isn’t about proving that I can plan without AI. I want to get my own thoughts onto the page before a model gives them structure, so I write down what I think we’re building, why it should exist, how the main pieces relate, and any constraints I already know about. I’m not trying to produce polished tickets at this stage, just trying to build the plan.
If I ask AI to take the wheel too early, it can produce something that looks complete before I’ve decided what I actually want. It starts influencing the project, and it becomes easy to accept decisions I never intentionally made. Writing the first version myself gives me something concrete to revise and eventually hand off.
Then I use AI to work through the plan
Once I have that first draft, I bring it into a planning assistant. There is no specific reason, but I prefer ChatGPT for planning and Claude Code for implementation. Use whatever works best for you. I begin by asking the assistant to walk through the plan and explain it back to me. We go over the goal, constraints, assumptions, and dependencies, and if it misunderstands something, I correct it before that misunderstanding turns into a series of implementation tasks.
This review often finds useful gaps. Maybe I left a dependency unstated. Maybe two requirements conflict. Sometimes the assistant asks about a decision I didn’t realize I still needed to make.
Only after its understanding matches mine do I ask it to divide the project into phases and individual tasks. I review that breakdown too. The generated plan is still a proposal until I agree that the order, scope, and dependencies make sense. I decide what the product needs to do, use the planning assistant to organize the work, and give the coding agent one approved piece at a time. Whatever comes back still needs my review.
Patent concerns aren’t limited to brand-new products
I ask about possible patent concerns while I’m planning a new product. I also ask when an existing product is getting a substantial feature, changing a core technical approach, entering another market, or changing how an important function works.
This is only an early warning. It is not a patent search, a legal opinion, or a freedom-to-operate analysis. A model can miss a relevant patent, misunderstand a claim, or point to something that sounds similar but doesn’t apply.
If it finds a patent document that might be relevant, I record the concern and investigate it. A similar idea appearing in a patent does not automatically mean the implementation falls within an enforceable claim. Depending on what I find, I might change the approach, keep records for later review, or speak with a patent professional before launch.
I check again if the design changes significantly and before those changes are released commercially. No warning from the model does not mean the product is clear to operate.
Turning the plan into tickets
Once the phases are settled, I ask the planning assistant to create individual tickets. A project might use identifiers such as:
UI-001: Build the initial account screenBE-001: Add the account creation endpoint
Those prefixes are just examples, and a useful naming scheme depends on the project. I need to be able to refer to the same task in the plan, a commit, a discussion, or a completion report without any confusion.
The tickets can live in Jira, GitHub issues, Markdown files inside the repository, or some combination of those systems. I prefer keeping a local copy in the project. The agent can read the wider plan and see what has already been completed. The tickets are also versioned with the code, which lets me review requirement changes with the implementation.
There is an obvious risk when a ticket exists in two places: they can drift apart. I designate one system as authoritative and decide how updates get copied to the other. Otherwise, the agent may implement an old local ticket while the team is discussing a newer version in Jira.

What I want in a completion report
As development begins, I ask the coding agent to leave a completion report beside each ticket. This gives the next session something better than an old chat transcript or a pile of code from which it has to reconstruct every decision.
The report tells me what was completed, how the agent verified it, and whether the result differs from the ticket. I also want to know what was left out, what still needs work, whether the implementation introduced a new dependency, and whether any security, privacy, licensing, contractual, or patent concerns came up.
I don’t want a diary of every file the agent opened or every command it ran. For a small ticket, the report can be short:
Added route replacement without creating a new history entry. Existing navigation guards and cleanup hooks still run. Added tests covering replacement, unknown routes, and cleanup order. All router tests pass. No changes were made to the public route configuration format.
A basic format is enough for most tasks:
## Completed
- Added route replacement without adding a history entry.
- Preserved navigation guards and cleanup behaviour.
- Added coverage for replacement and invalid routes.
## Verification
- Unit tests pass.
- Lint and type checking pass.
## Notes
- No public API changes.
- Manual Roku-device testing was not performed.
The report gets longer when the implementation differs from the plan, affects several systems, introduces a compromise, or leaves something unverified. A small ticket should usually produce a small report, and I still read the actual changes regardless of how complete the report appears.
I want assumptions stated before they turn into code
Agents have to fill in gaps. If a ticket doesn’t say where state belongs or which component owns a behaviour, the agent may choose an answer and keep going.
The choice itself may be reasonable. The problem is that I may not see it until several files and tests have been built around it. By then, it’s tempting to keep repairing the generated solution simply because so much work has already gone into it.
Before a larger change begins, I ask what the agent found in the repository, what it inferred from that evidence, and what still needs confirmation. This matters even more in an established codebase. The agent can read what exists today, but it doesn’t know why every decision was made. Something that looks accidental may be there because of a platform restriction, a customer requirement, or an old production problem.
When a fix fails
AI can be surprisingly good at debugging. It can trace state, compare code paths, and connect details that are easy to miss during a manual review. The trouble starts when the first fix doesn’t work and the agent responds to the newest error with another guard, fallback, or caller change. Each edit looks plausible on its own, but nobody has established why the original failure happened.
When I see that pattern, I stop asking for code and ask:
- What is the root cause?
- What evidence supports that conclusion?
- Why did the previous fix fail?
- What is the smallest change that would test the explanation?
If it can’t answer those questions, I don’t let it make another edit.
Reusing code requires more than finding it
In a well-structured project, the agent usually finds the related utilities, services, and components. I still need to review whether any of them should be reused.
Two pieces of code may look similar while serving different responsibilities. Extending one can create coupling that becomes painful later. The reverse happens too: the agent creates another helper because it didn’t recognize that an existing abstraction already owns the behaviour. Before implementation, I ask the agent to show me the related code, who uses it, what responsibility it currently owns, and why the new behaviour should extend it or remain separate.
I don’t insist on reuse. I want to see that the decision was made with knowledge of what already exists. Clear naming and component boundaries make this easier. A better prompt may improve the search, but it can’t fix ambiguity that already exists in the project.
Comments for people and agents
I’ve had better results with comments that are short and specific, especially when they explain intent that isn’t obvious from the implementation. A useful comment may describe a guarantee, a constraint, a non-obvious side effect, or an edge case the caller needs to understand:
// Converts an API response into a cached user record.
// Preserves the existing display name when the response omits it.
function updateCachedUser(response: UserResponse) {}
That preservation rule is useful context. A longer comment that narrates how the function reads fields and updates properties adds very little because the agent can already read those steps in the code.
For a more important function, I may use a compact contract:
/**
* Replaces the active route without adding a history entry.
*
* Preconditions:
* - `route` must already be registered.
*
* Guarantees:
* - Existing route cleanup completes before activation.
* - Navigation guards still run.
*
* Throws:
* - `UnknownRouteError` when the route is not registered.
*/
function replaceRoute(route: string) {}
I use a longer comment when the function genuinely needs one. What matters is recording the facts that aren’t obvious from the code and keeping them accurate. Even a short comment can send the agent in the wrong direction once it becomes stale.
Architecture still needs direction
Agents sometimes build more structure than a feature needs. A straightforward request comes back with interfaces, factories, configuration layers, and abstractions for future scenarios that may never happen. The resulting code may be tidy, but it can still introduce structure the product doesn’t need.
I decide where the code belongs, which component owns it, which performance tradeoffs are acceptable, and how much abstraction the current feature justifies. If a modest change starts touching unrelated files, I stop and ask why each one needs to change.
I read the assertions, not just the test results
AI-generated tests often improve my coverage, but a passing test can still describe the wrong behaviour. The agent may make a mistaken assumption in the implementation and then write a test that expects exactly that result. Heavy mocking can also remove the integration where the actual risk lives. Everything passes, but the ticket is still wrong.
For each generated test, I check what requirement it protects, why the expected value is correct, and whether it would fail for the defect I care about. The test suite helps me verify the work, but I still have to decide what the correct product behaviour is.
Long sessions need written handoffs
Context problems show up most often for me during long sessions. The agent revives an approach we rejected earlier, forgets why a boundary was established, or becomes so focused on the latest error that it loses the original task.
When that starts happening, I write a progress summary. I write down what is finished, what we decided, what we rejected, which questions are still open, and what the agent should do next. I use that summary to begin the next phase or start a fresh session. The plan, ticket, and completion reports give the new session most of the context it needs without relying on the old conversation.
I still review every change
After the agent finishes a ticket, I inspect the diff and compare it with the original requirement. I want to understand why each affected file changed before I accept the work or build anything else on top of it.
That is the same basic standard I apply to code written by another person. Developers misunderstand requirements, overlook side effects, and choose abstractions that don’t fit. Agents do too. Clean formatting, sensible names, tests, and a confident explanation don’t prove that the change belongs in the project.
This is why I keep the tasks small. Each ticket should give me one change I can realistically review, with clear acceptance criteria and a reasonable limit on what the agent should touch. I don’t want to review an entire project phase in one diff, and I don’t want a passing test suite to become an excuse for not understanding what changed.
Frequent commits or checkpoints help, as does asking for a plan before substantial edits. If I can’t review the diff carefully, I let the task get too large.
What this is doing to my own skills
Daily AI use has expanded the range of technical work I’m comfortable approaching, but it has also reduced how often I perform some fundamentals manually. I’m not convinced that is entirely good or bad. Spending less time on repetitive implementation leaves more time for architecture and product decisions, while skills that aren’t practised can still get rusty.
I don’t need to type every line myself, but I do need enough understanding to spot a false premise, a broken convention, or a tradeoff the product shouldn’t accept.
There is some research behind that concern. In an Anthropic study involving an unfamiliar Python library, the AI-assisted group performed worse overall on a later comprehension assessment. Participants who asked conceptual questions showed better understanding than those who mainly delegated the work. That is only one study, but its findings line up with how I try to work: ask questions, check my understanding, and don’t hand over all of the thinking.
A Canada and US legal checkpoint
TKSS Software is Canadian and works with US clients, so I also need to consider the rules and risks in both countries.
- Patents: Patent rights are territorial, so searching in Canada alone doesn’t address US exposure. CIPO describes freedom-to-operate work as obtaining a legal opinion about whether commercial activity may conflict with existing patent rights. An AI warning or a search result is not that opinion.
- Inventorship: The USPTO’s current guidance for AI-assisted inventions applies the existing inventorship standard and allows only people to be identified as inventors. If AI is involved in inventive work, it makes sense to keep records of the human contribution.
- Confidentiality and privacy: The Government of Canada warns that some suppliers may inspect submitted information or use it for training. I don’t submit source code, credentials, customer data, proprietary documents, or unpublished invention details until I understand the service’s terms and controls. I also don’t assume that a conversation with an AI assistant is confidential or protected by legal privilege. Canadian privacy regulators have published additional principles for organizations using generative AI.
- Licences and contracts: Suggested code and new dependencies still need provenance and licence review. Customer agreements may also restrict third-party AI services, data locations, subprocessors, or ownership of deliverables.
AI can point out something worth investigating. It can’t replace a legal review. Material patent, licensing, privacy, or contractual questions need qualified advice in the relevant jurisdiction.
Before I accept the work
Before I accept an agent’s work, I need to answer a few questions:
- Why does this change belong here?
- What assumptions does it depend on?
- What existing behaviour does it preserve?
- Why is this level of abstraction justified?
- What do the tests actually demonstrate?
- Can I reverse the change cleanly if the direction is wrong?
- Does it raise a security, privacy, licensing, contractual, or patent concern that needs another kind of review?
If I can answer those questions, the tool has probably saved me time without taking the project somewhere I don’t understand. If I can’t, I stop. I go back to the ticket, review the assumptions, and look at the changes already made before deciding what happens next.
This is the process I’ve settled into after several months of daily use. I expect AI to remain part of my development workflow, but its output only moves forward after I understand and review what it changed.
This article provides general information, not legal advice. Patent, privacy, licensing, and contractual questions should be assessed by qualified professionals in the relevant jurisdictions.
About the author: Tyler Smith is the President and Lead Developer at TKSS Software. He works with AI-assisted development tools across project planning, implementation, debugging, testing, and code review.