How I use AI
Author: Ramesh Kanjinghat
Published: 2026-10-26
I’ve spent a good amount of time experimenting with AI coding tools. Like many developers, I’ve tried different editors, models, agents, prompts, and workflows. Some experiments worked well; others didn’t.
Over time, I’ve come to believe that getting good results from AI isn’t just about choosing a better model or writing a clever prompt. A big part of it comes down to how much context you give the agent, how clearly you communicate your expectations, and how much control you retain over the work.
I’ve gradually built a small system around how I work with AI. It isn’t particularly sophisticated, and it isn’t tied to any one tool. It consists mainly of a set of Markdown files, a few working principles, and a development workflow I expect agents to follow.
I don’t want to explain myself in every conversation
One of the first things I noticed when using AI coding agents was how repetitive the interactions could become. Every new conversation involved explaining the same things:
- Understand the existing architecture before making changes.
- Follow the conventions already established in the repository.
- Don’t introduce unnecessary abstractions.
- Don’t modify unrelated code.
- Write tests when introducing new behavior.
- Don’t commit or push anything without asking me.
These aren’t instructions specific to one feature. They’re expectations I have regardless of which repository I’m working in or which AI tool I’m using. Repeating them in every conversation made little sense.
I wanted a way to establish these expectations once and have the agent follow them consistently. That’s when I started building my own AGENTS.md and companion files.
AGENTS.md is the operating contract
I maintain a central AGENTS.md file that defines how I expect an AI agent to work with me and my repositories. It isn’t a collection of coding tips or a place to dump every instruction I can think of. I treat it as the global operating contract between me and the agent.
One of its most important sections concerns user control. I explicitly distinguish between discussing an action and authorizing it. Saying “Looks good” doesn’t mean the agent can commit the changes, and approving an implementation plan doesn’t automatically authorize a Git push, a pull request, or a deployment. Any operation that changes persistent or external state requires explicit approval.
This might sound overly cautious, but I think it matters. AI agents are increasingly capable of running commands, interacting with external systems, and making changes beyond the files in front of them. Just because an agent can perform an operation doesn’t mean it should have permission to.
Another section covers how I expect the agent to approach an unfamiliar codebase. Before making changes, it should understand the requirement, inspect the repository, review existing implementations and tests, identify dependencies, and raise any concerns or ambiguities. I don’t want an agent to start implementing something based solely on a Jira description.
I also have instructions around scope: make the smallest change that solves the problem, avoid unrelated refactoring, and don’t silently expand the scope of an approved task. These are principles I want applied consistently, whatever the language, framework, or repository.
Why I don’t put everything in AGENTS.md
My AGENTS.md could easily grow into a very large document covering every possible situation. I don’t think that’s a good approach. Not every instruction is relevant to every task. If I’m making a code change, the agent doesn’t need detailed guidance on reviewing pull requests or implementing Jira tickets.
Instead, I separate global instructions from situation-specific ones. I call these specialized documents companion files. The global AGENTS.md tells the agent which companion to load depending on the task:
| Situation | Companion file |
|---|---|
| Writing or modifying code | CODE-COMPANION.md |
| Writing or changing documentation | DOCUMENTATION-COMPANION.md |
| Git and GitHub operations | GITHUB-COMPANION.md |
| Implementing a Jira ticket | JIRA-TICKET-IMPLEMENTATION-COMPANION.md |
| Working on learning notes | LEARNING-COMPANION.md |
This gives me two benefits. The global instructions stay focused on principles that apply everywhere, while each companion can go into much more detail about its own workflow without weighing down every conversation.
My CODE-COMPANION.md, for example, tells the agent to inspect git status and git diff before editing, preserve existing uncommitted changes, and implement one step at a time. It also establishes a specific working pattern:
- Implement one approved step.
- Run the applicable tests and validation.
- Explain what changed and why.
- Report the validation results.
- Stop and wait for my instruction before continuing.
I strongly prefer this to an agent making a large number of changes at once and presenting everything at the end.
The companion also makes testing mandatory wherever applicable. New behavior should have tests, changed behavior should have updated tests, and bug fixes should have regression tests where appropriate. It explicitly forbids weakening or removing tests just to make an implementation pass.
These are just a few examples, but they illustrate the idea: rather than hoping the agent infers my expectations, I make them explicit.
The instructions themselves need to be maintained
Instructions shouldn’t be static. As I work with AI, I encounter situations where an existing instruction isn’t sufficient, where two instructions conflict, or where I want to introduce a new working principle. I don’t want to mention something once in a conversation and hope the agent remembers it next time.
So I’ve added a dedicated instruction-governance section to AGENTS.md. It tells the agent to watch for requests that introduce new instructions, conflict with existing ones, or deviate from an established workflow. When that happens, the agent must call it out before proceeding.
For example, suppose I ask an agent to skip the usual step-by-step process and make several changes in one go. Rather than silently accepting the deviation, it should explain which existing instruction is affected and ask whether I want this to be:
- A global change that should update AGENTS.md.
- A local change that should apply only to a particular repository or task.
- A one-time exception that doesn’t require changing any instruction files.
Once I confirm the scope, the agent updates the appropriate documents, preserving existing instructions and checking for contradictions.
I particularly like this approach because it creates a feedback loop: the way I work with AI evolves, and the instructions evolve with it. The goal isn’t to keep adding more rules. It’s to make sure the rules reflect how I actually want to work.
I want the agent to understand before it changes anything
Instructions are only part of the picture. How an agent approaches a task matters just as much.
For anything beyond a trivial change, I expect it to understand the existing implementation before proposing a solution. I don’t want an agent to see a requirement, generate code immediately, and then spend several iterations correcting assumptions it could have identified upfront.
My preferred workflow is:
Understand → Investigate → Identify concerns → Plan → Review → Implement → Test → Report
The important part is that implementation doesn’t automatically follow investigation. I want to see the proposed approach, the affected components, the trade-offs, and any potential side effects before anything is built.
For larger tasks, this gives me an opportunity to challenge the approach, eliminate unnecessary work, and provide domain knowledge that might not be obvious from the codebase.
For smaller, straightforward changes, I don’t need all that ceremony. My instructions define a fast path for small, reversible changes that are fully specified. The point isn’t to slow development down; it’s to match the amount of process to the complexity and risk of the task.
I care more about verifiable results than generated code
Code generation and software engineering aren’t the same thing. An agent can produce code that looks reasonable, compiles, and even passes a few tests without necessarily being the right solution.
I don’t judge an agent by how much code it produces or how quickly it produces it. I want to know whether the change actually solves the problem without introducing regressions.
That’s why my instructions emphasize testing and validation. The agent should run relevant tests, linters, type checks, and static analysis where applicable, and report exactly what it ran, what passed, what failed, and what wasn’t tested.
One instruction I particularly like is:
Never claim validation that was not actually performed.
It sounds obvious, but there’s a real difference between an agent saying the implementation should pass the tests and actually running them.
I also don’t expect every piece of generated code to be perfect. What matters is that the result meets the engineering standards I’d expect from a human contributor.
This is where layered quality controls become important. Tests, static analysis, code review, existing architectural conventions, and explicit approval boundaries all contribute to confidence in the result. No single mechanism is sufficient on its own.
AI does the execution; I retain the engineering judgment
I don’t see AI as a replacement for understanding the system or making engineering decisions. I use it to accelerate the parts of development that can be delegated: exploring unfamiliar code, tracing dependencies, investigating bugs, proposing implementations, writing tests, and handling repetitive changes.
But I still want to make the decisions that matter.
Is this the right abstraction? Does this change belong in this component? Are we introducing unnecessary complexity? Does the approach respect the existing architecture? Is the additional functionality actually needed?
These questions require context beyond the immediate implementation. An agent can make a technically reasonable decision that is still wrong for the system I’m working on.
That’s why I put so much emphasis on instructions, explicit approval, scope control, and incremental validation. I want agents to do substantial work, but I also want to understand what they’re doing, why they’re doing it, and when they need my approval.
An evolving workflow
I’m still experimenting with different models, editors, and coding agents. The tools will keep changing, and some of today’s practices may become unnecessary as agents improve. But I suspect the underlying principles will remain useful.
Give the agent the context it needs. Make expectations explicit. Separate global rules from task-specific guidance. Let it investigate before changing things. Define how quality is measured. And be deliberate about what it’s allowed to do.
The most useful thing I’ve built around AI isn’t a complicated prompt or an elaborate collection of tools. It’s a set of instructions that captures how I work as an engineer and makes those expectations reusable.
I’d rather spend my conversations solving engineering problems than repeatedly explaining to an agent how I expect it to work.