Skip to main content

Agentic AI — Developer Onboarding Guide

Who this is for: Engineers joining the team who will work with AI agents in their daily workflow. What this is not: A tutorial on prompting AI. This is about how we expect you to work alongside it.


The Core Mindset

You are the author. The agent is your tool.

When code ships, you own it. This means you need to understand what was changed, why it was changed, and whether it actually solves the right problem.

After every agent session, you should be able to answer two questions:

  1. What did the agent change, and why?
  2. What did I decide, and what did the agent decide?

If you can't answer both — the review isn't done.


Before You Start

Always start from a clean git state — no matter what.

git status
# should show nothing uncommitted

git checkout -b feature/your-task-name
# never run agents on main or develop

Write down what you want before you prompt. Even two or three sentences. This forces clarity and gives you something to compare the output against later.

Task: Refactor UserService to stop making direct DB calls.
All queries should go through UserRepository.

In scope: src/services/user.service.ts
src/services/user.service.spec.ts

Out of scope: everything else — do not touch controllers, auth, or migrations

Constraints: don't change public method signatures, don't add new packages

If you skip this step, you will end up with a 12-file diff when you asked for a 2-file change. It happens every time.


Giving the Agent Good Context

Agents work with what you give them. The examples below show what that looks like across the three stacks we use.

Python (FastAPI / Django)

Bad prompt:

fix the user endpoint

Good prompt:

We use FastAPI with SQLAlchemy (async) and a repository pattern.
The get_user endpoint currently calls db.execute() directly.
It should call user_repo.find_by_id() instead.

Here's the current endpoint:

@router.get("/users/{user_id}")
async def get_user(user_id: int, db: AsyncSession = Depends(get_db)):
result = await db.execute(select(User).where(User.id == user_id))
user = result.scalar_one_or_none()
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user

Here's the UserRepository interface: [paste it]

Refactor get_user to use user_repo.find_by_id().
Raise our custom UserNotFoundError, not HTTPException directly.
Do not change the route path or response shape.
Return only the updated function.

The difference is specificity. The second prompt leaves almost no room for the agent to guess.


Go (services / APIs)

Bad prompt:

add error handling to the payment service

Good prompt:

We use Go 1.22 with a standard errors package and wrap errors using fmt.Errorf with %w.
All handlers return (Result, error) — we never panic in handlers.

Here's the ProcessPayment function that needs error handling added:

func (s *PaymentService) ProcessPayment(ctx context.Context, req PaymentRequest) (PaymentResult, error) {
charge, err := s.gateway.Charge(req.Amount, req.CardToken)
// missing: handle gateway timeout separately from general errors
if err != nil {
return PaymentResult{}, err
}
return PaymentResult{ChargeID: charge.ID}, nil
}

Add handling that:
1. Wraps gateway timeout errors as ErrGatewayTimeout (already defined in errors.go)
2. Wraps all other gateway errors as ErrPaymentFailed
3. Logs the raw error before wrapping (use our Logger, not fmt.Println)

Return only the updated function. Do not change the function signature.

Next.js (App Router / API Routes)

Bad prompt:

make the dashboard load faster

Good prompt:

We use Next.js 14 App Router. Data fetching happens in Server Components —
we do not use useEffect for data fetching.

The /dashboard page currently fetches user stats and recent activity in two
separate sequential awaits inside the page component:

export default async function DashboardPage() {
const stats = await getUserStats(userId)
const activity = await getRecentActivity(userId)
return <Dashboard stats={stats} activity={activity} />
}

Refactor to fetch both in parallel using Promise.all.
Keep it as a Server Component — do not convert to a Client Component.
Do not add any new dependencies.
Return only the updated page component.

Reviewing What the Agent Did

This is the most important part of the whole process. Use whichever method fits how you work — GUI, terminal, or both. The goal is the same: read every change before you stage it.

Step 1 — See what was touched

Terminal:

git diff --name-only    # every file that changed
git diff --stat # lines added/removed per file

VS Code — Source Control tab (Ctrl+Shift+G / Cmd+Shift+G): Open the Source Control panel. Every changed file appears under Changes. The number next to each file tells you how many lines shifted. If you see a file in that list that wasn't in your scope declaration — stop and understand why before going further.

Cursor / JetBrains: The Source Control or Git panel (usually in the left sidebar or bottom bar) shows the same file list. In JetBrains, use Cmd+9 / Alt+9 to open the Git tool window.

If a file appears that wasn't in your declared scope — stop. The agent touching your Go middleware when you only asked it to change a payment service function is not a small thing.


Step 2 — Read the diff, line by line

You have two good options depending on where you're most comfortable. Use both when something feels unclear.

Option A — VS Code / Cursor Source Control (GUI)

Click any file in the Changes list. VS Code opens a side-by-side diff view automatically.

Left panel  = what the file looked like before
Right panel = what the agent changed it to

Red lines are deletions. Green lines are additions. Scroll through every changed file. If something looks unexpected — right-click the file and choose Revert Changes to undo just that file, or use Stage Selected Ranges to accept only specific lines.

The key habit: don't click "Stage All Changes." Instead, click each file individually, read the diff, then right-click → Stage Changes only when you've actually read it.

Option B — Terminal with git add -p (patch mode)

git add -p

This shows you every chunk of changes one at a time. For each chunk:

KeyWhat it does
yStage this chunk — you're happy with it
nSkip this chunk — don't stage it
sSplit the chunk into smaller pieces
eEdit the chunk manually before staging
dSkip this file entirely
?Show all options

What a good chunk looks like — stage it:

@@ -24,8 +24,12 @@ func (s *PaymentService) ProcessPayment(...) {
- if err != nil {
- return PaymentResult{}, err
- }
+ if errors.Is(err, gateway.ErrTimeout) {
+ s.logger.Error("gateway timeout", zap.Error(err))
+ return PaymentResult{}, fmt.Errorf("processing payment: %w", ErrGatewayTimeout)
+ }
+ if err != nil {
+ s.logger.Error("gateway error", zap.Error(err))
+ return PaymentResult{}, fmt.Errorf("processing payment: %w", ErrPaymentFailed)
+ }

This matches what you asked for. You can explain every line. Press y.

What a suspicious chunk looks like — skip it:

@@ -1,6 +1,7 @@
import (
"context"
"fmt"
+ "github.com/some-new-package/retry"
)

You didn't ask for a retry package. Press n, then ask the agent why it added this before deciding whether to accept it.

Which to use when

SituationRecommended
Most day-to-day reviewsVS Code / Cursor Source Control — faster to navigate across files
You want to accept only specific lines within a filegit add -p — finer control than the GUI
Large multi-file agent outputStart with GUI to get an overview, then git add -p for files that need careful review
You're in a terminal-only environmentgit add -p entirely

Both are valid. The point is that you read every change — not that you use a specific tool to do it.


Step 3 — Questions to ask yourself per changed file

QuestionWhat you're checking
Can I explain what this code does?If not, it's not ready to merge
Did the agent change a value I should have set? (timeout, limit, retry count)That's your decision, not the agent's
Are error cases handled, or just the happy path?Agents frequently miss edge cases
Is anything sensitive getting logged?Easy for agents to add debug logs with real data
Does go.mod / requirements.txt / package.json show new deps?Verify explicitly — don't assume

Step 4 — Run the checks

Python:

pytest
ruff check .
mypy src/

Go:

go test ./...
go vet ./...

Next.js:

yarn test
yarn lint
yarn tsc --noEmit

Zero new errors before you commit. If tests were passing before the agent session and they're failing now — that's the agent's output breaking something, and it needs to be fixed before merge.


What You Decide vs. What the Agent Decides

Keep this distinction clear.

You decide — always:

  • What gets built and how systems connect
  • Timeouts, rate limits, retry counts, expiry values
  • Who can access what (auth, permissions, role checks)
  • What goes in scope for the session
  • Any default values that affect production behavior

The agent decides — and you verify:

  • How to implement what you specified
  • Variable naming, code structure, loop patterns
  • Boilerplate, docstrings, test scaffolding

A concrete example of getting this wrong:

You ask the agent to add a password reset flow. It comes back with a working implementation. Everything looks good. You merge it.

Three weeks later, someone notices the reset token expires in 24 hours. You never specified an expiry — the agent picked 24 hours on its own. Your security policy requires 15 minutes. The agent made a security decision that was yours to make.

Check every value the agent introduces that has business or security implications. If you didn't specify it, ask yourself whether you should have.


Commit Convention

Tag your commits so the team can tell what happened:

# You directed it, agent helped implement, you made meaningful edits
git commit -m "feat(users): add pagination to getUserList [ai-assisted]"

# Agent wrote it, you reviewed and accepted mostly as-is
git commit -m "chore(tests): generate unit tests for AuthService [ai-generated]"

# You wrote it, you ran an agent review pass
git commit -m "refactor(payments): simplify retry logic [ai-reviewed]"

In your PR, add a short note:

## AI Usage
Files the agent touched: src/services/user.service.ts, src/services/user.service.spec.ts
What I specified: method signatures, error types, repository pattern usage
What the agent generated: implementation, test bodies, inline comments
Anything I overrode: agent set token TTL to 60min → I changed to 15min

Things That Go Wrong (and How to Avoid Them)

The agent touched files you didn't ask it to touch. Always run git diff --name-only first. If something unexpected is in there, understand it before you accept it.

You accepted code you didn't understand. If a function came back and you're not sure what it's doing — ask the agent to walk through it before you stage it. "Explain this function line by line" is a completely valid follow-up prompt.

The agent picked values that had real consequences. Timeouts, rate limits, permission checks. These are yours. Specify them upfront or check every instance the agent introduces them.

Tests passed before the session, failing after. Don't merge. The agent broke something in the process of helping you. Find it.

You pasted real credentials or customer data into the prompt. Never do this. Replace all sensitive values with placeholders before sharing any code with an AI tool.

# Before pasting — replace this:
DATABASE_URL = "postgresql://admin:realpassword@prod.db:5432/app"

# With this:
DATABASE_URL = "postgresql://USER:PASSWORD@HOST:PORT/DB"

Quick Reference

Terminal:

# Before every session
git status # clean state
git checkout -b feature/task-name # feature branch

# After every session
git diff --name-only # what files changed
git diff --stat # how much changed
git add -p # review chunk by chunk (recommended for careful review)

# Python
pytest && ruff check . && mypy src/

# Go
go test ./... && go vet ./...

# Next.js
yarn test && yarn lint && yarn tsc --noEmit

GUI (VS Code / Cursor):

  1. Open Source Control tab — Ctrl+Shift+G / Cmd+Shift+G
  2. Check the Changes list — every file the agent touched is here
  3. Click each file → read the side-by-side diff before staging
  4. Right-click → Stage Changes per file (never "Stage All" without reading)
  5. Use Revert Changes on any file you want to discard entirely

Before merging, answer these:

  • Do I understand every changed line?
  • Did I make the decisions that were mine to make?
  • Do all checks pass?

This document lives in the synapse documentation wiki. If something in here is unclear or out of date, raise it with your tech lead.