A Field Guide

Technical Communication

How to write bug reports, pull requests, technical specs, and Slack messages that actually get read, understood, and acted on.

🎯 Part 1: Before You Write
📝 Part 2–4: Core Formats
🤝 Part 5–6: Alignment
🤖 Part 7–8: Docs & AI
⚠️ Part 9: Failure Patterns

The One Idea That Makes Everything Else Make Sense

Technical communication fails for one reason more than any other: the writer makes the reader do work they shouldn't have to do.

Every piece of technical writing has a reader who needs to act. Review this code. Fix this bug. Make a decision on this proposal. Understand this system. The writer's job is to make that action as cheap as possible — to give the reader exactly what they need to proceed without having to ask questions, infer context, or figure out what's being asked of them.

When a ticket sits unactioned, it's usually because the reader can't tell what to do with it. When a PR gets minimal review, it's often because the reviewer doesn't understand why the change was made. When a spec generates endless discussion, it's frequently because readers aren't sure what decision is actually being requested.

🎯 The Question
Before writing anything: what does my reader need to do, and what's the cheapest way to give them everything they need to do it?

This isn't about being concise for its own sake. Sometimes more context is exactly what the reader needs. It's about serving the reader's action, not demonstrating your thoroughness.

Part One
Before You Write
Four questions that take thirty seconds and prevent hours of back-and-forth.

The Four Questions

Before writing any technical document, answer these four questions. The answers shape everything — format, length, emphasis, what to include and what to leave out.

1. Who is the reader?

A teammate who knows the system deeply? A new hire who doesn't? An engineer in a different timezone who has no context on what you've been working on? Your future self in six months?

2. What do they need to do?

Review code. Fix a bug. Approve a proposal. Understand a system. Just be informed. The format, length, and emphasis changes dramatically based on the answer.

3. What do they already know?

Don't explain what they know — that's noise. Don't assume they know things they don't — that's a gap they'll have to fill. The calibration between these two is most of what makes technical writing good.

4. What's the one thing they need to take away?

If the reader gets to the end and remembers one thing, what should it be? If you don't know, you haven't thought through what you're writing yet.

💡 Tip
These questions take thirty seconds to answer and prevent hours of back-and-forth. Most unclear technical writing is unclear because the writer never answered them.
Part Two
Bug Reports
The anatomy of a bug report that actually gets fixed.

Bug Reports — Writing One That Gets Fixed

A bug report has one job: give whoever is fixing the bug everything they need to reproduce it, understand it, and fix it — without having to ask you anything.

Every question the reader has to ask is a round-trip delay before the bug gets fixed.

What a bad bug report looks like

❌ Bad
Title: Search is broken

Description: When I search for something the results are wrong. This is happening on my account and it's causing problems. Can someone look into this?

This report makes the reader do all the work: What kind of search? What results are wrong — wrong content, wrong order, no results? What were you searching for? What did you expect? What did you get? What account? What environment? When did this start?

What a good bug report looks like

✅ Good
Title: Product search returns no results for queries containing apostrophes

Steps to reproduce:
1. Go to /search
2. Type "women's shoes" in the search box
3. Press Enter

Expected: Results for women's shoes
Actual: "No results found" — even though products with this term exist

Environment: Production, Chrome 121, macOS. Also reproduced in Firefox.

Additional context: Started after last Thursday's deploy. Queries without apostrophes work fine. Confirmed on my account (user ID 8841) and on a test account.

The reader can reproduce this immediately. They know what's expected and what's happening. They have a hypothesis (apostrophe handling, probably in the search query parser) and a timeframe (post-deploy). No questions needed.

The anatomy

Title: Specific enough that someone reading a list of tickets knows what this is about without opening it. "Search broken" is not a title — it's a category. "Product search returns no results for queries with apostrophes" is a title.

Steps to reproduce: Numbered, specific, starting from a known state. Not "go to search and try a query" — the exact query. Not "log in" — log in as whom, to where?

Expected vs. actual: Two explicit statements. Don't make the reader infer what you expected.

Environment: Browser, OS, version, account, URL. Seems like overhead until you're debugging something that only happens in Safari on iOS.

Additional context: When did it start? Is it intermittent? Does it affect all users or specific ones? What have you already tried? This is where a good bug report becomes genuinely useful — the context you have as the person who found the bug often points directly at the cause.

💡 Minimum viable bug report
If you can't include everything, prioritize in this order: title, expected vs. actual, steps to reproduce, environment. A report with just those four things is actionable. One without them usually isn't.
Part Three
Tickets & Issues
Writing something that gets done — not just filed.

Tickets and Issues — Writing Something That Gets Done

A ticket is a bug report that isn't necessarily a bug — it might be a feature, a task, a refactor, a question. The same principle applies: reduce the cost for the reader to act.

But tickets have an additional audience problem: the person who writes the ticket and the person who does the work are often different, and they often have different levels of context. The writer knows why it matters; the worker may not. The worker needs to know what done looks like; the writer may not have thought that through.

The elements that matter

Clear title: Specific enough to distinguish from every other ticket. "Improve performance" tells you nothing. "Reduce checkout page load time from 4s to under 2s on mobile" tells you the problem, the target, and the context.

The why: Why does this matter? What breaks or suffers without it? "This is causing a 12% cart abandonment rate on mobile" is more motivating than "users have complained." It also helps the implementer make judgment calls — when they're choosing between two approaches, knowing the goal helps them pick the right one.

The what: What does done look like? What's the acceptance criteria? Vague tickets get implemented in whatever way seems reasonable to the person doing the work, which may not match what the requester had in mind.

What's not in scope: Especially for refactors and improvements, noting explicitly what you're not asking for prevents scope creep and gold-plating. "This ticket is only about reducing the initial load time — not redesigning the checkout flow."

Relevant context: Links to related tickets, relevant logs, designs, previous discussions. The information someone would need to get started — not everything you know, just the on-ramp.

🤖 What AI gets wrong about tickets
AI writes thorough tickets — but thoroughness and usefulness are different things. AI-generated tickets tend to include every possible consideration instead of the ones that actually matter, write long "background" sections that bury the actual ask, and omit the specific context only you have (the error logs, the user complaint, the business impact).

When using AI to draft a ticket, treat the output as a structure to fill in — not a finished product.
Part Four
Pull Requests
Writing the description that gets your code actually reviewed.

Pull Requests — Getting Your Code Reviewed

A pull request description is the sales pitch for your changes. The diff shows what changed. The description explains why it changed, what you considered, and what the reviewer should focus on.

Most PR descriptions are terrible. "Fixed the bug" or "Implemented the feature per spec" forces the reviewer to reverse-engineer your reasoning from the diff, which is slow and often incomplete. The reviewer ends up approving without fully understanding the change — which defeats the purpose of review.

What reviewers actually need

What problem does this solve? Not what the ticket says — what's the actual problem in plain language. "Users with apostrophes in their names couldn't complete checkout" is more useful than "Fixes #4821."

What approach did you take, and why? Not just what you did, but why this way rather than another. "I'm sanitizing the input at the form level rather than the database layer because [reason]" tells the reviewer whether your reasoning matches their understanding of the system.

What should they focus on? What are you most uncertain about? What's the tricky part? "I'm not sure about the error handling in line 47 — there might be an edge case I'm missing" is more useful than nothing, and invites the kind of review that actually catches problems.

What did you test? What manual testing did you do? What automated tests cover this? What edge cases did you check?

The structure that works

## What
One to three sentences. What does this PR do?

## Why
Why is this change being made? What problem does it solve?

## How
Brief description of the approach. Alternatives considered.

## Testing
What testing was done? What tests exist?

## Notes for reviewer
Specific things to look at. Concerns. Decisions you want a second opinion on.

You don't need all five sections for a small PR. A one-line bug fix needs less than a new feature. Scale the description to the complexity of the change.

The size problem

The single most common reason PRs get poor review is they're too large. A 2,000-line PR touching fifteen files gets a cursory look and an "LGTM" because no reviewer can hold it all in their head. A 200-line PR with a clear description gets real review.

If your PR is large, ask: can this be split? One PR for the refactor that makes the feature possible, and a separate PR for the feature itself. Smaller PRs take longer to prepare but significantly less total time to get merged — because review actually happens. For the git mechanics of branching, rebasing, and managing PRs, see the Git field guide.

💡 Screenshots for visual changes
For UI changes, screenshots or recordings in the PR description are disproportionately valuable. Before/after screenshots take thirty seconds to add and save the reviewer several minutes. Reviewers don't have to check out the branch to know what the change looks like.
Part Five
Technical Specs
Producing alignment, not discussion.

Technical Specs — Producing Alignment, Not Discussion

A technical spec (also called an RFC, design doc, or proposal) exists to produce a decision. Its job is to give stakeholders everything they need to reach alignment on an approach — not to document every consideration or demonstrate how much thinking you've done.

Most technical specs fail because they're written as documents rather than arguments. They present a proposal without clearly stating what the reader is being asked to decide, which means readers comment on everything rather than making the decision that needs to be made.

The elements of a spec that produces alignment

The problem statement: Clear, specific, and agreed upon before the solution is presented. If readers don't agree on the problem, any solution will generate debate. Spending one section establishing "here is the problem we are solving, and here is why it matters" is often the most important part of a spec.

The constraints: What are you working within? What can't change? What must be true of any acceptable solution? Constraints narrow the solution space and prevent debate about solutions that aren't actually available.

The proposed solution: What you're recommending, specifically. Not "we could consider" or "one option might be" — a clear recommendation, explained in enough detail to evaluate.

Alternatives considered: What else did you think about? Why did you reject them? This pre-empts the reader who was going to suggest the approach you already ruled out. "We considered X but rejected it because of Y" prevents that comment from derailing the discussion.

The decision you're asking for: Explicitly. "I'm looking for agreement on the database migration approach before starting implementation" or "I need a decision on whether we build this internally or use the vendor solution." Without a clear ask, readers don't know whether they're being informed or consulted.

Open questions: Things you haven't resolved and need input on. Separating "I've decided this" from "I haven't decided this and want feedback" focuses the discussion.

💡 The right length
A spec should be as long as it needs to be and no longer. A one-page spec that produces a decision is better than a ten-page spec that produces endless comment threads. If you find yourself writing more than three or four pages, ask: what is the actual decision that needs to be made here? Background is for appendices, not the main document.
Part Six
Asking Technical Questions
How you ask determines whether you get a useful answer — or start a round of clarifying questions.

Asking Technical Questions Well

How you ask a technical question determines whether you get a useful answer quickly or start a round of clarifying questions that delays what you need.

The XY problem

One of the most common failure modes in technical communication. You have problem X. You think solution Y will solve it. You ask about Y instead of X. The person you're asking helps you with Y — but Y doesn't actually solve X, and now you've both wasted time.

📝 Example
You're trying to get the last three characters of a filename. You decide to use the string length. You ask "how do I get the length of a string in bash?"

The real question is "how do I extract a file extension in bash?" — which has a direct, better answer.

Fix: Always describe the actual goal before the attempted approach. "I'm trying to [goal]. I thought [approach] might work but I'm stuck on [specific issue]."

What makes a technical question answerable

Context: What are you trying to accomplish? What system are you working in? What have you already tried?

The specific thing you're stuck on: Not "I don't understand X" but "I understand A and B, but I can't figure out how C relates to them."

What you've already tried: Prevents getting suggestions you've already ruled out and shows you've put in effort before asking.

What you've found: Relevant links, error messages, documentation you've consulted. This helps the person know what context you already have.

💡 Tip
A question that takes two minutes to write well gets a faster, better answer than one that takes thirty seconds to write poorly. The responder doesn't have to ask for the information you should have included — they can just answer.

Slack and async messages that get responses

Technical questions in chat have a specific failure mode: the question is too open-ended to answer quickly, so the reader moves on and forgets about it.

❌ Too open-ended
"Do you have a few minutes to chat about the auth flow?"

This requires the reader to make a commitment and schedule time.
✅ Directly answerable
"Quick question about the auth flow — when a token expires mid-session, does the refresh happen automatically or does the client need to handle it?"

This requires only a brief answer.

The more your question can be answered in a paragraph or less, the faster you'll get a response. If a topic genuinely needs a conversation, say explicitly what you're trying to figure out — it helps the other person prepare.

Part Seven
Documentation
Writing for your future self and others.

Documentation — Writing for Your Future Self and Others

Code documentation and internal docs are often treated as an afterthought. The result is systems that only the original author understands, onboarding that takes months, and the same questions asked over and over.

Comments: why, not what

Code shows what's happening. Comments should explain why — the reasoning, the constraint, the non-obvious decision.

❌ Explains the code
# Multiply by 0.9 to apply discount
price = base_price * 0.9
A comment that restates the code is noise.
✅ Explains the why
# 10% loyalty discount — hardcoded per business requirement
# in ticket #2841. Dynamic rates on the roadmap; see #3102.
price = base_price * 0.9
A comment that explains the reasoning is signal — especially when someone is debugging the code six months later and wondering why the value is 0.9.

READMEs that actually help

A good README answers the questions someone new to the project will have: what is this, how do I run it, how do I run the tests, where does the interesting code live, what are the gotchas.

The most important thing a README can do is give someone the fastest path to understanding and running the thing. Exhaustive documentation is less valuable than the ten sentences that let someone get oriented in five minutes.

Architecture Decision Records

An ADR (Architecture Decision Record) is a short document that captures an important decision: what was decided, why, and what alternatives were considered. They're small — one page — and enormously valuable when someone (including you, in a year) is trying to understand why the system is the way it is.

The format is simple: title, date, status, context (why was a decision needed?), decision (what was decided?), rationale (why this over alternatives?), consequences (what are the trade-offs?).

💡 Tip
The practice of writing ADRs pays for itself the first time someone asks "why did we do it this way?" and you have an answer instead of a guess.
Part Eight
AI for Technical Writing
Using it well means knowing what it's good at and where it fails.

AI for Technical Writing — Using It Well

AI is useful for drafting technical documents. It's also prone to specific failure modes that make AI-generated technical writing less useful than it looks.

What AI does well

Structure: AI is good at producing the skeleton of a document — the sections, the headers, the flow. Starting with AI structure and filling in your content is often faster than starting from a blank page.

Improving clarity: Paste a draft and ask AI to make it clearer, more concise, or better organized. This is often more useful than having AI write from scratch.

Filling in boilerplate: Standard sections (environment details in a bug report, testing section in a PR description) can be drafted by AI with minimal input.

Checking completeness: "What's missing from this bug report?" or "What questions would a reviewer have after reading this PR description?" AI can audit your document for gaps before you share it.

What AI gets wrong

It doesn't know your context. AI generates plausible-sounding technical communication that lacks the specific context only you have. The business reason this matters. The specific error message you're looking at. The history of the decision. AI produces generic; you need specific.

It optimizes for completeness, not action. AI-generated specs and tickets tend to be thorough rather than focused. They include every consideration and hedge every claim. The result reads like it was written by a committee — technically defensible but not driving anyone toward a decision.

It buries the ask. AI tends to present background and context before the actual request. In technical communication, the ask should usually come early, not after three paragraphs of context.

It writes confidently about things it doesn't know. AI will fill in specific details — error codes, API behavior, system specifics — that it doesn't actually know, in the same confident voice it uses for things it does know. In technical documents, invented specifics are worse than no specifics.

How to use AI for technical writing effectively

✅ The right workflow
Write the key information yourself first — the specific context, the actual problem, the real ask — then use AI to improve structure and clarity.

Reversing this (have AI write it, then edit) produces worse results because the AI fills in specifics with generic plausible-sounding content, which you then have to replace anyway.

Give AI the context it lacks: paste the relevant error message, describe the specific system, give it the actual ticket number and history. AI output is only as specific as its input. For more on structuring effective prompts — including context layering, format specification, and iteration techniques — see the Prompting field guide.

Always add back the things only you know. AI will produce a complete-looking document that's missing the one piece of context that would make it actually useful.

Part Nine
Patterns That Consistently Fail
Specific patterns worth recognizing — in your own writing and in others'.

Communication Patterns That Consistently Fail

These patterns appear in technical communication constantly. Recognizing them is the first step to avoiding them.

The context dump

Providing all available context without curating it. Every log line, every error message, every thing you tried, every person you talked to, in no particular order. The reader has to extract the relevant information themselves.

💡 Fix
Decide what's relevant before writing. The reader needs to reproduce the problem and understand its scope — not read your debugging session.

The assumed background

Writing for a reader who knows everything you know. Using internal jargon without defining it. Referencing tickets or discussions without linking them. Describing a problem without explaining why it matters.

💡 Fix
Ask the four questions in Part 1. Who is your reader, and what do they know?

The disguised request

Writing several paragraphs of context and problem description without ever clearly stating what you're asking for. The reader reaches the end unsure whether you want them to fix something, make a decision, just be aware, or do something else entirely.

💡 Fix
State the ask explicitly. "I'm looking for someone to investigate this before Thursday." "I need a decision on approach A vs. B." "No action needed — just flagging for visibility."

The non-title title

A title so generic it could describe any issue in its category. "Performance issue." "Auth bug." "UI fix." These titles make it impossible to distinguish one ticket from another in a list.

💡 Fix
Write the title as a specific, declarative statement of the problem. "Login button unresponsive for users with SSO enabled on iOS Safari" is a title. "Login bug" is a category.

The endless thread

Back-and-forth async communication that should have been a short synchronous conversation. Each message requires the other person to re-establish context. The question gets answered, clarified, re-answered, qualified, and answered again.

💡 Fix
Recognize when async has become costly. Five messages in without resolution is usually the signal. "This might be faster as a quick call — are you free for ten minutes?" is not a defeat; it's efficient.

Quick Reference

The four questions before writing anything

  1. Who is the reader?
  2. What do they need to do?
  3. What do they already know?
  4. What's the one thing they need to take away?

Bug report checklist

  • Specific title (not a category — a specific problem)
  • Steps to reproduce (numbered, exact, starting from known state)
  • Expected vs. actual (both explicit)
  • Environment (browser, OS, account, URL)
  • Additional context (when it started, what you've tried, what you know)

PR description checklist

  • What this does (1–3 sentences)
  • Why it's being done
  • How (approach and key decisions)
  • Testing done
  • Notes for reviewer (what to focus on, what you're uncertain about)

Technical spec checklist

  • Problem statement (agreed before solution)
  • Constraints
  • Proposed solution with clear recommendation
  • Alternatives considered and rejected
  • The explicit decision being requested
  • Open questions

Good technical question structure

  • What you're trying to accomplish (the actual goal)
  • What you've already tried
  • What you've found
  • The specific thing you're stuck on

AI writing checklist

Patterns to avoid

  • Context dump — provide relevant context, not all context
  • Assumed background — write for the reader you have
  • Disguised request — state the ask explicitly
  • Non-title title — specific declarative statement, not a category
  • Endless async thread — recognize when a call is faster

What You Can Do Now

The next thing you write — a ticket, a Slack message, a PR description — answer the four questions before you start: who is the reader, what do they need to do, what do they know, what's the one thing to take away.

Then, before sending, ask: what questions will the reader have? If you can predict them, answer them in the document. Every predicted question you answer is a round trip you've eliminated.

That habit, applied consistently, is most of what separates technical communication that moves things forward from technical communication that generates more communication.