Skip to content

GitHub Copilot Agent Mode Explained

Lesson 5 of 8Intermediate → Advanced15 min readGitHub Copilot & AI Engineering · GitHub CopilotVerified: GitHub Copilot agent mode and cloud agent documentation, September 2026

Agent mode is where Copilot stops proposing and starts doing.

It determines which files to change, makes the edits, runs commands, reads the results and iterates until the task is done — in your local development environment, with your approval at each step.

What makes an agent different from chat that produces edits.

The agent loop

A cycle: goal, plan, action, environment feedback, and either iterate or finish. The feedback step is what distinguishes an agent from a generator.

GoalWhat you asked forPlanIts decomposition — readable, and worth readingActionEdit a file, run a commandEnvironment feedbackTest output, compiler errors — the only ground truthIterate or finishAdjust, or decide it is done

The feedback step is the whole difference. Chat produces code and stops. An agent produces code, runs your tests, reads the failure and fixes it. That loop is why multi-file changes are feasible and why the results are usually better than a single generation.

It is also where the risk lives. An agent that can run commands can run the wrong one, and an agent that decides it is finished has made a judgement about its own work.

The comparison, stated once properly.

Agent modeCopilot cloud agent
Execution environmentYour local machineGitHub-hosted, powered by GitHub Actions
Changes appear inYour workspaceA branch in the repository
SupervisionYou approve each actionNone while it runs
Credentials in scopeWhatever is in your environmentWhat the environment is configured with
Typical interactionActively watching, steeringDelegate and come back
OutputEdits you review locallyA pull request
Task assignmentA prompt in your editorAn issue, chat, the agents panel, @copilot
Good forWork where the goal shifts as you learnWell-specified, bounded tasks

Two rows deserve emphasis.

Credentials. Agent mode runs in your shell, with your environment. If you have production credentials loaded, so does it. The cloud agent runs in an environment somebody configured deliberately, which is a different — and in this respect better — property.

Supervision. With agent mode you can stop it mid-task. With the cloud agent you cannot, so the controls have to be set before it starts.

Neither is safer in general. They fail differently, which is why the choice is about the task.

The goal is clear but the path is not. Debugging, a refactor whose shape emerges as you go, a change touching code you do not know well. Supervision lets you redirect when the first approach is wrong.

You want to see it happen. Reviewing changes as they appear is faster than reviewing a completed pull request, and cheaper to correct.

It needs your local environment. A database running locally, a service you have port-forwarded, a build that depends on your machine’s configuration.

The change is exploratory. You might throw it away. That is fine locally and awkward as a pull request.

When it is the wrong tool: anything well specified enough to delegate, anything you do not want to watch, and anything where a pull request is the natural output.

The habits that separate useful agent sessions from ones you abandon.

Branch first.

Terminal window
git switch -c agent/attempt-1

One command, and the whole session becomes discardable. This is not distrust — it is the same precaution you would take before an experimental refactor, and it matters more here because an agent produces more changes faster.

State acceptance criteria, not steps.

Add a timeout parameter to HttpClient, default 30 seconds, threaded through to the request calls. Update the three call sites in services/ to read it from config. Add a test for the timeout path. Existing tests must pass.

That is judgeable. “Improve the HTTP client” is not, and an agent given it will improve something.

Read the plan. Where the agent produces one, this is the cheapest intervention point in the entire interaction. Correcting a plan costs a sentence; correcting six edited files costs a review.

Interrupt early. If the first two actions are heading somewhere wrong, stop. Agents commit to an approach and a long run in the wrong direction is harder to salvage than starting again.

Let it run the tests. The observe step is the value. An agent that cannot see the failure cannot fix it.

Review the diff, not the transcript. The transcript is the agent’s account of what it did. The diff is what it did — and git diff --stat frequently shows files nobody mentioned.

The strongest predictor of a good agent session is task size, and the instinct to give it something big because it can handle big things is usually wrong.

Well-sized tasks share properties:

  • A goal you can state in three sentences
  • Files you could name in advance, roughly
  • A test or observable outcome that says whether it worked
  • Small enough that the diff is reviewable in ten minutes

Oversized tasks look like: “migrate the codebase to the new API”, “add tests to this module”, “refactor the service layer”. These are projects. An agent given one produces a large diff that nobody reviews properly, which defeats the purpose.

The productive decomposition is the same one you would use for yourself. “Migrate the codebase” becomes “migrate services/orders.py, keeping the public interface unchanged, tests passing” — a task with an answer, repeated.

There is a second reason beyond reviewability: context. A large task fills the window, and the symptoms of that — vagueness, repetition, forgotten constraints — appear as the agent getting worse partway through, which reads like model failure and is a scoping problem.

Where supported, an agent can spawn subagents to handle delegated work in an isolated context.

The mechanism matters for one specific reason: context isolation. A subagent asked to “read these forty files and report which handle authentication” does the reading in its own context and returns the answer. Forty files never enter the main conversation.

That is the difference between a session that stays coherent and one that fills up on exploration before starting the actual work.

Where it helps most:

Broad search across a codebase, where you need a conclusion rather than the material.

Parallel independent subtasks, where three things can proceed at once without interacting.

Background work that does not need to block the conversation.

Where it is worth caution: a subagent’s work is less visible than the main agent’s. What you get back is its summary, and the summary is subject to the same “an account is not evidence” rule as everything else. For anything consequential, check what it actually did rather than what it reported.

Agent mode asks before it edits files and before it runs commands. Those two categories deserve different levels of attention.

File edits are reversible. Git has them, your editor has undo, and you were going to review the diff anyway. Approving these readily is reasonable.

Terminal commands are not reversible by your editor. A command that deletes something, pushes something, or calls an API has effects Git does not track and undo does not reach. These deserve reading.

The categories worth pausing on every time:

  • Anything with rm, --force, --hard or DROP
  • Anything that pushes, deploys or publishes
  • Anything calling an external API with credentials
  • Anything installing software
  • Anything touching a file outside the workspace

The rule from the CLI cluster applies here identically: generating a command is research; running it is a decision.

What “it can act” actually means, because the tool list determines the risk profile.

Read files. The least dangerous and most used. An agent reading widely is an agent with context.

Search the workspace. How it finds what to read. Non-deterministic, and the reason attaching key files still helps even in agent mode.

Edit and create files. Reversible via Git, which is why branching first matters so much.

Run terminal commands. The consequential one. Everything from pytest to rm -rf is the same category of capability, distinguished only by what you approve.

Fetch from the network, where enabled. Reading documentation is useful; it is also a route by which external content reaches the agent’s context, which matters for prompt injection.

MCP tools, where configured. Whatever those servers expose — which for a write-capable server can be a great deal. See MCP + GitHub.

Browser tools, in some surfaces, letting it load and interact with a running application.

The security framing worth carrying: an agent’s capability is the union of its tools and its environment’s credentials. Restricting tools without restricting the shell it runs in leaves the larger half of the problem open — which is why “do not run agent sessions in a shell with production credentials” appears in this article rather than only in the security cluster.

Scope creep. Asked to fix a bug, it also reformats the file, updates an unrelated import and renames a variable for clarity. None of it wrong; all of it unrequested, and it makes the diff harder to review. Narrow criteria and git diff --stat catch it.

Declaring victory early. The tests it knows about pass, so it stops. Whether those tests cover the thing you asked for is a separate question.

Working around a failure instead of fixing it. A test fails, so it adjusts the test. Sometimes correct; frequently not, and it is a specific thing to look for in the diff.

Context exhaustion on long sessions. Presents as vagueness, repetition, or losing a constraint you set earlier. Start a fresh session rather than pushing through.

Confident wrong APIs. The same failure as chat, now committed to files. The compiler is the check.

Plausible test that asserts nothing. Particularly with mocks. Break the code deliberately and confirm the test fails.

Repository instructions matter more in agent mode than anywhere else, because an agent makes many decisions without asking and each one defaults to whatever the model considers normal.

The instructions that pay off most in agentic work, specifically:

Conventions it would otherwise get wrong repeatedly. The logger to use, the error type to raise, the HTTP client wrapper. An agent editing six files applies the convention six times, right or wrong.

Constraints on what to touch. “Do not modify files in legacy/.” “Generated files under proto/ must not be edited by hand.” An agent has no way to know a directory is frozen.

Testing expectations. “Every new function needs a test in the matching test_ file.” This changes what the agent considers done.

What not to do. “Do not add dependencies without stating it explicitly.” “Do not reformat files you are not otherwise changing.” That second one directly addresses the scope creep problem above and is one of the highest-value instructions for agent work specifically.

The important caveat, repeated because it is easy to lose: instructions shape behaviour, they do not enforce it. An instruction not to touch legacy/ reduces the chance and does not prevent it. Where something must not happen, the control is a tool restriction, a hook, or a ruleset — not a sentence in a Markdown file.

The same rigour as any contribution, plus two specific checks.

  1. git status and git diff --stat first. The file list is the highest-signal thing, and it is invisible if you only read the files you were thinking about.

  2. Read the diff file by file. Not the summary.

  3. Look for the unrequested. Reformatting, unrelated imports, a changed comment, an added dependency.

  4. Check the tests actually test. Break the code; confirm they fail.

  5. Run everything yourself. The agent’s report is a claim; a run is evidence.

  6. Stage selectively. Committing in logical pieces produces better history and forces a closer read.

Steps 1 and 3 are the ones specific to agent work. A human contributor rarely reformats a file incidentally; an agent does it routinely.

The shape end to end, on a realistic task: a failing test in an unfamiliar module.

  1. Branch. git switch -c agent/fix-order-rounding.

  2. Establish the goal precisely.

    tests/test_orders.py::test_total_rounding is failing. Investigate why and fix it. Do not change the test’s assertions — if the test is wrong, tell me rather than editing it. Other tests must continue to pass.

    The second sentence is doing real work. Without it, “adjust the test until it passes” is a valid reading of the task and a common outcome.

  3. Let it read. The first actions should be running the test and reading the implicated files. If it starts editing before running anything, redirect.

  4. Read the diagnosis before the fix. An agent that can say why the test fails has understood something; one that goes straight to a change may be pattern-matching.

  5. Let it fix and re-run. The loop.

  6. Review. git diff --stat, then the diff. Check specifically: did it change only what was needed, and did it leave the assertions alone?

  7. Run the full suite yourself.

  8. Commit in logical pieces, or discard the branch and redo it yourself if the approach was wrong — which is a legitimate outcome and costs only the time already spent.

Step 2’s constraint is the transferable part. Naming the thing you do not want it to do is more effective than describing what you want, because the undesirable shortcut is usually the easiest path to a passing state.

Knowing when to stop is a skill, and the instinct to keep steering is usually wrong past a certain point.

Abandon when the approach is wrong, not just the execution. If the agent has understood the task and made a mess, steering works. If it has misunderstood the task, twenty more messages will produce a well-executed version of the wrong thing.

Abandon when the diff has grown past what you will review. A change you will not read carefully is a change you should not merge, and the honest response is to discard and redo it in smaller pieces.

Abandon when you are correcting the same thing repeatedly. That is a signal the constraint belongs in instructions rather than in this conversation — write it down, start fresh, and it applies from the beginning.

Abandon when you no longer understand the state. You are on a branch; git switch main and git branch -D cost nothing, and continuing from confusion is how a recoverable session becomes an afternoon.

The cost of abandoning is only the time already spent, which is a sunk cost the moment you notice. The cost of continuing a bad session is that time, plus a diff you have to review with less confidence, plus the chance that something wrong survives review because you were tired of looking at it.

Confusing it with the cloud agent. Different environment, supervision and output.

Working on a branch you care about. One command prevents it.

Vague goals. An agent given “improve this” will improve something.

Skipping the plan. The cheapest correction point in the session.

Approving terminal commands by reflex. Editor undo does not reach a shell command.

Running with production credentials in the environment. It inherits your shell.

Reading the transcript instead of the diff. The transcript is its account.

Trusting “the tests pass”. Which tests, and do they assert anything?

Pushing through context exhaustion. A fresh session with a tight goal beats a drifting one.

How closely to watch is the real decision in agent mode, and it is not a fixed setting.

Watch closely when: the codebase is unfamiliar to you, the change touches something security-relevant, the agent is working in a language or framework you cannot review fluently, or the task is exploratory enough that “wrong direction” is likely.

Watch loosely when: the change is mechanical, the tests are good, the blast radius is a branch you will delete anyway, and you can review the final diff competently.

Do not watch at all — which means you should be using the cloud agent instead. Agent mode’s design assumes a human present; running it unattended gets the supervision cost without the benefits of proper delegation.

The failure mode worth naming: supervision decaying into acknowledgement. After twenty approvals that were all fine, the twenty-first gets approved without reading. That is human, predictable, and the reason narrow tool allowances matter more than vigilance — an allowance you configured while thinking clearly beats an approval you granted while tired.

The practical mitigation is the same as everywhere in this pillar: make the safe path the default. Pre-approve the read-only and obviously-safe command classes so the prompts you do see are the ones worth reading.

Agent mode is a capable colleague working on your machine, with your credentials, who asks before each action and believes they are finished when the tests they know about pass. Supervision is not distrust — it is the mechanism that makes the loop converge on what you actually wanted.

  • The observe step — running things and reading the result — is what makes it an agent
  • Agent mode is local and supervised; the cloud agent is GitHub-hosted and delegated
  • Agent mode inherits your shell environment, including credentials
  • Branch first; it makes the session discardable
  • Acceptance criteria are what make the result judgeable
  • The plan is the cheapest place to correct a wrong approach
  • File edits are reversible; terminal commands are not
  • Scope creep, early victory and adjusted tests are the characteristic failure modes
  • git diff --stat before reading the diff catches the unrequested changes

Use a disposable repository with tests.

  1. Branch. Give the agent a task with explicit acceptance criteria.

  2. Read the plan before it acts. Predict: would you have caught a wrong approach here?

  3. Watch the first two actions. Predict: does it read before editing?

  4. Let it run the tests. Introduce a failure deliberately partway through. Predict: does it notice and correct, or work around it?

  5. When it finishes, run git diff --stat. Predict: are there files you did not expect?

  6. Break the code the new test covers. Predict: does the test fail?

  7. Give a second agent a deliberately vague goal. Compare the diff size with the specified one.

  8. Delete the branch.

AI-assisted engineering learning pathEleven lessons on getting value from Copilot and agents without giving up review discipline.