Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Professional English for Developers  Module 5 – Emails and chat

Team chat etiquette, threads and shorthand

Ask the question in your first chat message, keep replies in threads, decode LGTM, PTAL and WIP, and share code and logs as text, never as screenshots.

  • Beginner
  • 20 minutes
  • Examples run with Node.js 24.21.0, quickjs 0.32.0 and Python 3.14.8
  • By MySmartCoPilot
Free core, Pro depth: 7 of 20 minutes free
Free: Put the question in the first message, and the replies in a thread · Shorthand saves typing only when the reader knows it. With a pass: 3 in-depth parts and 3 interview answers, about 13 minutes.

What you will learn

  • Start a chat with the question itself, not a bare hello, and keep replies in threads
  • Use and decode chat shorthand such as LGTM, PTAL, WIP, FYI and OOO
  • Format code, logs and errors as text in code blocks, not as screenshots
  • Choose between chat, email, a ticket and a call for a given message

Before you start

Six chat messages asked one colleague for help: “hi”, “r u there?”, three fragments and a screenshot of the error. The question arrived in message 5, and the error never arrived as text. Sent as one message, the same request holds the question in its first line and the error in a code block: Text marked as code, in chat or Markdown usually with three backticks on the lines before and after it, and shown in a fixed-width font exactly as typed., and gets its answer the first time the colleague looks.

Good team chat etiquette comes down to three habits. Put the greeting and the question in one message, and keep the replies in a thread (in chat): A chain of replies attached to one chat message, which keeps a discussion together and out of the main flow of the channel.. Use shorthand such as LGTM, PTAL and WIP only with readers who know it, and give a time instead of ASAP. Share code, logs and errors as text, never as pictures of text.

Put the question in the first message, and the replies in a thread

A message that says only “hi” makes the reader answer a greeting before they learn what you need. The page nohello.net compares it to calling someone on the phone, saying hello, and then putting them on hold. Its advice is short: “Just ask the question!” You can still be friendly, in the same message. Step through one morning in Pune, first the slow way, then in one message:

Interactive · message by message A bare hello, and the morning it costs Step through one morning. Watch when the question reaches Arjun, then compare it with the same question in one message.
A bare hello, and the morning it costs, step 6 of 6. Messages so far: Kavya to Arjun: "hi"; Arjun to Kavya: "hi, what's up?"; Kavya to Arjun: "the build is failing…"; Kavya to Arjun: build-error.png; Kavya to Arjun: one message, question first; Arjun to Kavya: the fix, at 09:41.Kavyaasked in one goArjunanswered at once"hi""hi, what's up?""the build is failing…"build-error.pngone message, question firstthe fix, at 09:41

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. A bare "hi". 09:02 IST. The nightly build has failed, and Kavya writes "hi" to Arjun, then waits for him to answer before she asks anything.
  2. Arjun answers the greeting. 09:41 IST. Arjun comes out of a review, sees "hi" and answers "hi, what's up?". He has nothing to work on yet.
  3. The question, an hour late. 10:01 IST. Kavya is back from her stand-up and writes "the build is failing, can someone check pls". The question reaches Arjun 59 minutes after her first message.
  4. A screenshot of the error. Arjun asks which error. Kavya sends a screenshot of the log. He cannot copy the text to search for it, so he asks for the log as text, and the next question waits again.
  5. One message instead. Back to 09:02 IST. This time Kavya sends one message: the greeting, what failed and when, the question with a time and its zone, and the error as text in a code block.
  6. Answered at the first look. 09:41 IST. Arjun comes out of the review, reads the question and the error, and knows the fix. The answer arrives the first time he looks, with no greeting to answer first.

The question reached Arjun 59 minutes after the first “hi”, and even then the error was a picture he could not search. Asked in one message, it was answered at 09:41, the first time he looked. Chat is asynchronous communication: Communication in which the reader answers when they can, not at once, as in email and most team chat. A message that holds the whole question lets them answer in one go.: the reader answers when they can, so the message has to hold everything they need when they arrive. The program checks the six messages and the one that replaced them:

Six chat fragments and one message, checked JavaScript · chat/messy_clean.mjs
// One request for help in a team chat, sent two ways, checked for this lesson's habits: no bare greeting waiting for an
// answer, the question in the first message, logs as text in a code block instead of a screenshot, a time with its
// zone, no mass mention and no text-message spelling. It also counts the messages a reader has to read before
// learning what is asked.

const FENCE = '`'.repeat(3);
const MESSY = [
  'hi',
  'r u there?',
  'the build is failing',
  '[screenshot: build-error.png]',
  'can someone check pls',
  '@channel URGENT',
];
const CLEAN = [
  `Hi Arjun, the nightly build of payments-api failed at the migration step at 02:00 IST. Could you look at it before the 11:00 IST release check? Here is the error:\n${FENCE}\nERROR migrate: relation "refund_audit" already exists\n${FENCE}`,
];

const ASKS = /\?|\bcould you\b|\bcan (?:you|someone)\b/i;
function check(messages) {
  const flags = [];
  const askAt = messages.findIndex((m) => ASKS.test(m) && !/^r u there\?$/i.test(m));
  messages.forEach((m, i) => {
    if (/^(?:hi|hello|hey)[!. ]*$/i.test(m)) flags.push(`message ${i + 1} is a bare greeting: the reader waits for the question`);
    if (/^\[screenshot/i.test(m)) flags.push(`message ${i + 1} is a screenshot of text: nobody can copy or search it`);
    if (/@(?:channel|here|everyone)\b/i.test(m)) flags.push(`message ${i + 1} notifies everyone: mention only who must act`);
    for (const w of m.match(/\b(?:r u|pls|plz|u)\b/gi) ?? []) flags.push(`message ${i + 1}: "${w}" is text-message spelling`);
  });
  const all = messages.join('\n');
  if (!all.includes(FENCE)) flags.push('no code block: the error is not there as text');
  if (!/\b\d{1,2}:\d{2}\s?(?:IST|UTC)\b/.test(all)) flags.push('no time with a zone: the reader cannot tell how urgent it is');
  return { flags, askAt };
}

for (const [name, messages] of [['Messy', MESSY], ['Clean', CLEAN]]) {
  const { flags, askAt } = check(messages);
  console.log(`${name}: ${messages.length} message${messages.length === 1 ? '' : 's'}, the ask in message ${askAt + 1}, ${flags.length} flags`);
  for (const f of flags) console.log(`  - ${f}`);
}
console.log('\nThe clean message as the reader sees it:\n');
console.log(CLEAN[0]);

Output

Messy: 6 messages, the ask in message 5, 7 flags
  - message 1 is a bare greeting: the reader waits for the question
  - message 2: "r u" is text-message spelling
  - message 4 is a screenshot of text: nobody can copy or search it
  - message 5: "pls" is text-message spelling
  - message 6 notifies everyone: mention only who must act
  - no code block: the error is not there as text
  - no time with a zone: the reader cannot tell how urgent it is
Clean: 1 message, the ask in message 1, 0 flags

The clean message as the reader sees it:

Hi Arjun, the nightly build of payments-api failed at the migration step at 02:00 IST. Could you look at it before the 11:00 IST release check? Here is the error:
```
ERROR migrate: relation "refund_audit" already exists
```

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node messy_clean.mjs

Once the question is out, keep the answers together. Slack’s help centre puts it plainly: “Threads help you to create organised discussions around specific messages”, without clutter in the channel. Reply in the thread of the message you answer, and @mention: A person's name tagged with @ in a chat message, which notifies that person. A mention of the whole channel notifies everyone in it. only the people who must act; a mention of the whole channel wakes everyone. Across time zones, schedule a message for the reader’s morning instead of sending it into their night: chat tools such as Slack can schedule a message to send later.

Key idea

Put the greeting, the question, the details and a time with its zone in one message, then keep every reply in its thread.

Checkpoint

Check: The question in the first message, replies in threads

  1. Question 1 of 2 Which first message to a busy colleague follows the lesson?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Hi Arjun, the nightly build of payments-api failed at the migration step at 02:00 IST. Could you look at it before the 11:00 IST release check?

    Put the greeting, the question, the details and a time with its zone in one message.

  2. Question 2 of 2 Where do you answer a question someone asked in the team channel?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: In the thread of their message

    Reply in the thread, and mention only the people who must act.

Shorthand saves typing only when the reader knows it

Team chats are full of shorthand, and each piece stands for a whole sentence. Review threads are where it is densest:

Shorthand Means
LGTM looks good to me: the reviewer approves the change
PTAL please take a look, or another look after changes
WIP work in progress: not ready for review yet
nit a minor point, worth fixing but not blocking
FYI for your information: no action needed
OOO out of office

Google’s engineering practices define LGTM as what a code reviewer says when approving a change, and a nit as “a minor thing”. The Kubernetes contributor guide uses PTAL to ask a reviewer to take another look, and asks for WIP in the title of a pull request that is not ready for review. FYI is in the IETF’s glossary of internet terms.

Shorthand is a shared code, so it works only for readers who share it. Google’s style guide says not to use internet slang abbreviations such as tl;dr in documentation; chat is more relaxed, but a newcomer or a colleague who reads English as a second language may not know them, so expand them for those readers. And give a time instead of ASAP or EOD: “by 17:00 IST” means the same moment to everyone.

Not every message belongs in a chat at all: some go better in an email, a ticket or a call. And a reply of one word, or a lone emoji, can read as curt or mean different things to a colleague who does not know you.

Checkpoint

Check: Shorthand and the readers who know it

  1. Question 1 of 2 A reviewer writes "LGTM" on your pull request. What does it mean?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Looks good to me: they approve the change

    LGTM means "looks good to me", the reviewer's approval.

  2. Question 2 of 2 You write to a colleague who joined last week: "PTAL at PR #612 EOD." What should change?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Write it out, with a time and its zone: "Could you take a look at PR #612 by 17:00 IST today?"

    Expand shorthand for newcomers, and replace EOD and ASAP with a time and its zone.

A shorthand decoder, with when to avoid each one, run on a review message Pro: opens with a Pro, Premium or Ultimate pass

Knowing what shorthand means is half the skill; knowing when to write the words out is the other half. This part gives a decoder with a rule for each term, and runs it on a real-sized review message and its rewrite for a newcomer.

In this part:

  • A decoder with a rule for each term
  • A review message decoded, then rewritten for a newcomer

1 runnable example (JavaScript) · about 3 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Code and logs as text: a curly-quote failure, reproduced with real Git Pro: opens with a Pro, Premium or Ultimate pass

A picture of code cannot be copied, searched or read aloud, and text pasted from the wrong place can break the command it shows. This part reproduces one such break with real Git and shows the two habits that prevent it.

In this part:

  • Text, not pictures of text
  • A curly quote that breaks a command

2 runnable examples (Python) · about 4 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Choosing the channel, and replies that do not read as curt Pro: opens with a Pro, Premium or Ultimate pass

The same message can be right in a chat thread and wrong in an email, or the other way round. This part lets you choose the channel for a message of your own, and shows how short replies and reactions read to colleagues abroad.

In this part:

  • Chat, email, a ticket or a call
  • Short replies and reactions, read from abroad
  • Three rules to keep from the parts on shorthand, code and channels

about 7 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Practise: five fragments, one message

The exercise holds the five fragments a developer sent to a new colleague about a flaky test. Rewrite them as one message until the sample tests pass:

Exercise · Easy · JavaScript

Turn five chat fragments into one message

Kavya needs help from Lena, a QA engineer who joined the team last week. The test "pays with a saved card" in checkout.spec.ts has failed in about one run in five on CI since PR #640 was merged yesterday, with this error:

TimeoutError: waiting for selector "#pay-button" failed: timeout 5000ms exceeded

Kavya would like Lena to look at it before the release check at 16:00 UTC, and she can pair with her at 14:00 UTC. messages.mjs holds the five fragments Kavya first sent. Rewrite them as one message, inside the list:

  • the first line holds the question: what you need, with Could you …?;
  • it names the test file, checkout.spec.ts;
  • the error is text in a code block: three backticks on a line of their own, the error line, then three backticks again (write each line break as \n);
  • every time has a zone;
  • no bare greeting, screenshot, @channel or @here, text-message spelling such as pls or r u, and, because Lena is new, no shorthand such as ASAP, EOD, PTAL or WIP.

Starter code · messages.mjs

// Rewrite Kavya's five chat fragments as one message that Lena can act on. Keep the list: one string per message, with
// \n for each line break inside a message.
export const messages = [
  'hi Lena',
  'r u around?',
  'checkout test flaky again',
  '[screenshot: ci-failure.png]',
  'pls check ASAP',
];
The sample tests · messages.test.mjs
import { test, assert } from 'mysmartcopilot:test';
import { messages } from './messages.mjs';

// The habits of the lesson, as its chat checker reads them.
const FENCE = '`'.repeat(3);
const message = messages.join('\n');
const firstLine = (messages[0] ?? '').split('\n')[0] ?? '';

test('one message, not five', () => {
  assert.equal(messages.length, 1, `${messages.length} messages: put everything in one`);
});

test('the first line holds the question', () => {
  assert.ok(/\?/.test(firstLine) && /\b(?:could|can|would) you\b/i.test(firstLine), `ask in the first line, with "Could you …?": "${firstLine}"`);
  assert.ok(!/^(?:hi|hello|hey)\b[^?]*$/i.test(firstLine), 'a greeting alone makes the reader wait; add the question to it');
});

test('it names the test and gives the error as text in a code block', () => {
  assert.ok(message.includes('checkout.spec.ts'), 'name the test file: checkout.spec.ts');
  const lines = message.split('\n');
  const open = lines.indexOf(FENCE);
  const close = lines.indexOf(FENCE, open + 1);
  assert.ok(open >= 0 && close > open, 'put the error between two lines of three backticks');
  assert.ok(lines.slice(open + 1, close).some((l) => l.includes('TimeoutError')), 'the code block holds the error line, as text');
  assert.ok(!/\[screenshot/i.test(message), 'no screenshot: the error goes in as text');
});

test('every time has a zone', () => {
  const times = message.match(/\b\d{1,2}:\d{2}\b(?:\s?(?:UTC|IST|CET))?/g) ?? [];
  assert.ok(times.length > 0, 'say by when: the release check is at 16:00 UTC');
  for (const t of times) assert.ok(/(?:UTC|IST|CET)$/.test(t), `give "${t}" its zone`);
});

test('no mass mentions, text-message spelling or shorthand', () => {
  assert.ok(!/@(?:channel|here|everyone)\b/i.test(message), 'mention only who must act: Lena');
  const speak = message.match(/\b(?:r u|pls|plz|u)\b/i);
  assert.ok(!speak, `"${speak?.[0]}": write the words out`);
  const short = message.match(/\b(?:ASAP|EOD|EOW|PTAL|WIP|IMO|OOO|LGTM|TL;DR)\b/);
  assert.ok(!short, `"${short?.[0]}": Lena is new, so write it out`);
});
A hint

Start with the greeting and the question on one line: "Hi Lena, could you look at a flaky test in checkout.spec.ts before the 16:00 UTC release check?" Then the facts, then the error between two lines of three backticks.

The sample tests run on this device, in your browser (QuickJS): nothing is sent to mysmartcopilot.com. The first run downloads JavaScript (about 0.6 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Then try the questions on first messages, threads and shorthand:

Practice that adapts to you

Practise this lesson

7 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 7 What does nohello.net compare a bare "hello" in chat to?

    Choose one answer.

    Show the answer: Question 1 of 7

    Answer: Calling someone on the phone, saying hello, then putting them on hold

    "Just ask the question!" in the same message as the greeting.

  2. Question 2 of 7 Which belong in a first chat message that asks for help?

    Choose every answer that is right.

    Show the answer: Question 2 of 7

    Answer:

    • the details, with the error as text
    • the question
    • the greeting
    • a time with its zone

    Greeting, question, details and a time with its zone, all in one message.

  3. Question 3 of 7 Your question in the team channel is for Arjun and Lena. Whom do you mention?

    Choose one answer.

    Show the answer: Question 3 of 7

    Answer: @Arjun and @Lena

    Mention only the people who must act.

  4. Question 4 of 7 It is 08:30 IST in Pune, which is 23:00 in Toronto, and your question for a colleague there is ready. What do you do?

    Choose one answer.

    Show the answer: Question 4 of 7

    Answer: Write it now and schedule it for the start of their morning

    Across time zones, schedule the complete message for the reader's morning.

  5. Question 5 of 7 What does WIP at the start of a pull request title tell reviewers?

    Choose one answer.

    Show the answer: Question 5 of 7

    Answer: It is not ready for review yet

    WIP means work in progress, not ready for review yet.

  6. Question 6 of 7 Which line replaces "Please check ASAP"?

    Choose one answer.

    Show the answer: Question 6 of 7

    Answer: Could you check it by 15:00 UTC today?

    Replace ASAP and EOD with a time and its zone.

  7. Question 7 of 7 You turn a long chat explanation into a README section that starts "TL;DR: run make setup first." What changes?

    Choose one answer.

    Show the answer: Question 7 of 7

    Answer: Write it in plain words, such as "In short:", because Google's style guide keeps internet slang out of documentation

    Chat can be relaxed, but documentation uses plain words instead of internet slang.

Interview questions

Warm-up (fresher to mid-level): Why is “hi” on its own a weak first message in a work chat?

Because the reader has to answer a greeting before learning what you need, and if either of you is busy the question arrives an hour later. Chat is asynchronous, so the first message should hold the greeting, the question, the details and a time with its zone. Then the reader can answer the first time they look.

Three longer questions of this module’s bank build on this lesson:

  1. Fresher to mid

    A teammate keeps posting screenshots of stack traces in the team channel, and nobody can search or copy them. How do you ask them to change, and what do you show them?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Mid to senior

    A production bug needs a decision from a client, your lead and the QA team today. Which channels do you use for what, in which order, and what does each message say?

    Model answer, Pro. First step and follow-ups

  3. Mid to senior

    Your team's chat is full of shorthand such as PTAL, WIP and nit, and two new hires say they feel lost. What do you change, and how do you get the team to keep the change?

    Model answer, Pro. First step and follow-ups

Key takeaways

  • Team chat etiquette starts with one message: the greeting and the question together, with the details and a time with its zone, so the reader can answer the first time they look.
  • Reply in threads and mention only the people who must act.
  • Use shorthand only with readers who know it, and give a time instead of ASAP or EOD.

Terms in this lesson

@mention
A person's name tagged with @ in a chat message, which notifies that person. A mention of the whole channel notifies everyone in it.
asynchronous communication
Communication in which the reader answers when they can, not at once, as in email and most team chat. A message that holds the whole question lets them answer in one go.
code block
Text marked as code, in chat or Markdown usually with three backticks on the lines before and after it, and shown in a fixed-width font exactly as typed.
smart quotes
Curly quotation marks, such as “ ” and ‘ ’, which word processors can put in place of the straight marks " and ' as you type.
thread (in chat)
A chain of replies attached to one chat message, which keeps a discussion together and out of the main flow of the channel.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.