learn-tech-writing-with-phoebe / Session 4 of 8
Learn Tech Writing with Phoebe · Session 4 of 8

The README: milestone 1

The README is the most-read document in any repository and the front door for the 30-second reader you met in Session 1. Today everything from Sessions 1-3 lands on one page: Pulse gets a complete, honest README, assembled from material you already wrote.

🟡 Core Practitioners Data & AI teams 45 min live + self-study depth
0-3 · Welcome 3-18 · Concepts (live cards) 18-40 · Build-along on Pulse 40-45 · Q&A
Part 0

Why this session exists

Every repo visitor opens the README first, and most open nothing else. It is where Session 1's 30-second reader makes the read-or-leave call, where Session 2's crisp sentences earn their keep, and where Session 3's scannable structure gets its hardest test. You have already written the raw material: an audience statement, scope statements, a numbered run procedure, a config table. Today we assemble it.

Live - presented in session Self-study - read after class ★ Try it now exercise Sources: makeareadme.com + Google style guide
★ What you walk out with today A complete, honest README.md for Pulse - name, description, install, quickstart with expected output, usage tables, configuration reference, project status - built from Sessions 1-3 material and verified with a timed 30-second test. This is the course's first shipped milestone.
Part 1 · covers makeareadme.com

Anatomy of a README 7 min live

makeareadme.com gives the canonical section order: Name, Description, Badges, Visuals, Installation, Usage, Support, Roadmap, Contributing, Authors and acknowledgment, License, Project status. The craft is not filling all twelve - it is choosing which your reader needs, in that order, and skipping the rest on purpose.

Name + description what it is · who it's for · scope + non-scope Quickstart prerequisites · install · 3 commands Usage commands + expected output · output columns Configuration - every key, one table Project status - honest, dated The 30-second scan lands HERE and rarely goes deeper Order = reader priority: run it first, tune it later, history last The top band wins or loses the whole page. Spend your best sentences there.
🔍 Click to zoom - README anatomy as a page skeleton: the bands Pulse needs, in the canonical order
LiveThe section order, and what Pulse skips3 min▶

makeareadme.com's advice is blunt: write the README before you publish, keep it in Markdown at the top of the repo, and when in doubt, too long beats too short. But "long" means depth in the sections you keep, not keeping every section. Pulse is an internal pipeline, so we choose:

SectionPulse verdictWhy
Name, DescriptionKeepThe 30-second scan lives here
Installation, UsageKeepThe primary audience action: run it
ConfigurationKeep (added)Pipelines live and die by their config
Project statusKeepTells a newcomer this repo is alive
Badges, VisualsSkipNo CI to badge, nothing visual to show - decoration
Roadmap, Contributing, LicenseSkipInternal repo: no external contributors, no license question

Every skip is a decision, not an omission. If Pulse ever goes open source, the Self-study card below has the full template waiting.

makeareadme.com's full order, next to what Pulse keeps ✗ Full 12-section template Badges, Visuals: decoration Roadmap, Contributing: N/A License: no OSS question ✓ Pulse's 4 kept sections Name, Description: the scan Install, Usage: run it Configuration, Status: alive Every skip is a decision: Pulse chose four sections a reader needs, not the generic twelve.
🔍 Click to zoom - every skip is a decision, not an omission
LiveDescription = your Session 1 statements, landing2 min▶

You do not write the description from scratch - you already wrote it. Session 1's scope, non-scope and audience statements ARE the description paragraph:

  • Scope: "Pulse turns raw event CSVs into daily metrics with a LOW-volume alert."
  • Non-scope: "It does not schedule itself and does not serve dashboards - it produces one CSV."
  • Audience: "Written for analysts new to the team; assumes you can run Python scripts from a terminal."

Three sentences, and the 30-second reader knows what this is, what it is not, and whether it is for them. That is the entire job of the top band.

★ Try it nowTake a repo you own. Write its description as exactly three sentences: 1. What it does (scope) 2. What it deliberately does not do (non-scope) 3. Who it assumes you are (audience) If sentence 2 is hard, your repo has a scope problem, not a writing problem.
Self-studyThe full 12-section template, for open-source repos3 min read▶

When a repo faces the public, the sections Pulse skipped start earning their place. The full makeareadme.com order: Name, Description, Badges, Visuals, Installation, Usage, Support, Roadmap, Contributing, Authors and acknowledgment, License, Project status.

  • Badges answer "is this maintained and passing?" at a glance - build status, coverage, package version.
  • Visuals earn their place for anything with a UI or an output worth seeing; a screenshot beats three paragraphs.
  • Contributing matters the moment a stranger can send a pull request: how to set up a dev environment, run tests, and what you will and will not merge.
  • License is non-negotiable for open source - no license means nobody can legally use it, which is usually not what you meant.
  • Project status is the kindest section in the template: "development has slowed, looking for maintainers" saves a stranger a month of betting on abandonware.
Part 2 · covers Google style guide, computer interfaces

Code on the page 6 min live

A README full of commands lives or dies on whether those commands actually work when pasted. Google's developer documentation style guide has precise rules for text that touches code - fonts, placeholders, samples - and they all serve one goal: the reader can copy, paste, run, and verify.

LiveCode font, bold UI, and CAPS placeholders3 min▶

Three visual conventions carry almost all of Google's computer-interface style:

  • Code font for anything code-related: filenames (config.yaml), commands (python3 pulse/ingest.py), column names (event_id), values (LOW). The font itself tells the reader "this string is literal - type it exactly".
  • Bold for UI elements: "click Run", "open the Settings tab". Pulse has no UI, so this rule mostly waits - but your BI tools and cloud consoles need it constantly.
  • Placeholders in capitalized italic code font: PULSE_RAW_DIR, PROJECT_ID. The capitals scream "replace me"; regular code font whispers "type me literally". Confusing the two is how a reader ends up with a folder literally named PULSE_RAW_DIR.

The companion rule: commands must be exactly copy-pasteable, and every command shows its expected output. For Pulse's sample data the run prints 10 rows staged, then 8 rows kept, then the metrics path - so the README says so, and the reader knows within a minute whether their setup works.

Before - unverifiableRun the scripts in order (adjust paths as needed): python ingest.py python clean.py python metrics.py You should see some output if it worked.
After - copy, paste, verifyRun the three steps from the repo root, in this order: python3 pulse/ingest.py # expected: 10 rows read, 10 rows staged python3 pulse/clean.py # expected: 8 rows kept (1 duplicate + 1 invalid type removed) python3 pulse/metrics.py # expected: wrote pulse/data/metrics/daily_metrics.csv
LiveExample hygiene: safe names, teaching data2 min▶

Google's rules for examples are safety rules as much as style rules:

  • Reserved example domains only: example.com and friends exist precisely so your docs never point readers at a real site. Never a colleague's real email, never a real customer ID, never production data pasted "just to show the shape".
  • Code samples must be runnable and follow the language's own conventions; comments explain why, not what. A sample that errors on paste teaches the reader to distrust the whole doc.
  • Teaching data is designed, not sampled. Pulse's events_2026-07-01.csv has exactly 10 rows and deliberately includes one duplicate event_id, one invalid click event type, and one timezone-naive timestamp. That is not sloppiness - it is a fixture. It guarantees every reader sees the pipeline actually filter something: 10 in, 8 out, every time.
Real world

The demo that paged a stranger. A team's onboarding doc used a real internal service URL as its example. New hires dutifully pasted it, and the service owner got a small wave of malformed test traffic every onboarding week - and eventually an alert at 3am. One find-and-replace to example.com ended it. Example hygiene is incident prevention.

Self-studyLinks that say where they go2 min read▶

Google's linking rule fits in one line: link text describes the destination, never "click here" or "this page". "See the configuration reference" tells the reader what they get before they commit a click; "click here" tells them nothing and reads terribly in a screen reader's link list.

Link text: what the reader knows before they click ✗ Vague link text "Click here" for setup "This page" has the details Reader must click to find out ✓ Descriptive link text "See the configuration reference" Link the noun, not "click here" Reader knows the destination first Link text is the promise the reader reads before they click; name the destination, not the action.
🔍 Click to zoom - name the destination, never click here
  • Make the destination's name the link: "see How to diagnose a LOW alert day" - the title is the description.
  • Link nouns, not verbs: link "the config table", not "look at" the config table.
  • One link per destination per section is plenty; a paragraph with six links is a paragraph nobody finishes.
Build-along 1 of 3

Assemble the README's top half ★ 8 min · everyone follows

Create README.md at the top of the repo and build the bands that win the scan: name, description, prerequisites, install, quickstart. Almost every line already exists in docs/AUDIENCE.md and Session 3's numbered run procedure - this is assembly, not authorship.

Create README.md in the repo root. Title: # Pulse, then one plain-words subtitle line: "CSV events in, daily metrics out."

Write the description as the three Session 1 sentences: scope ("turns raw event CSVs into daily metrics with a LOW-volume alert"), non-scope ("no scheduler, no dashboard - it produces one CSV"), audience ("assumes you can run Python scripts from a terminal").

Prerequisites: Python 3.10+ and pyyaml. Install is one copy-pasteable line: pip install pyyaml.

Quickstart: the three commands in fixed order - python3 pulse/ingest.py, python3 pulse/clean.py, python3 pulse/metrics.py - each with its expected output: 10 rows staged, 8 rows kept, then pulse/data/metrics/daily_metrics.csv written.

Writing tip The expected-output lines are the difference between a quickstart and a hope. "10, then 8, then the file path" gives the reader three checkpoints; if they see 10, 10, they know exactly where reality diverged from the doc.
Build-along 2 of 3

Usage, configuration, and the full skeleton ★ 8 min · build your own

The bottom half serves the reader who is past "does it run" and into "what does it mean": paste Session 3's config table, add an output-columns table, and document what a LOW alert actually says. Here is the complete skeleton, real commands and real config keys included.

Usage: one line per script saying what it validates, keeps, or writes - lifted from Session 2's rewritten notes.

Configuration: paste the S3 config table covering paths, events.valid_types, and alerts.min_daily_events.

Output: a columns table for daily_metrics.csv, and one sentence defining LOW: fewer than 50 events on that day after cleaning.

Project status: one honest dated line. Then commit - milestone 1 ships.

README.md - the full skeleton# Pulse CSV events in, daily metrics out. Pulse turns raw event CSVs into daily metrics with a LOW-volume alert. It does not schedule itself and does not serve dashboards - it produces one CSV. Written for analysts new to the team; assumes you can run Python scripts from a terminal. ## Prerequisites - Python 3.10+ - pyyaml: pip install pyyaml ## Quickstart Run from the repo root, in this order: python3 pulse/ingest.py # expected: 10 rows read, 10 rows staged python3 pulse/clean.py # expected: 8 rows kept (1 duplicate + 1 invalid type removed) python3 pulse/metrics.py # expected: wrote pulse/data/metrics/daily_metrics.csv ## Usage | Script | What it does | |--------|--------------| | ingest.py | Validates headers (needs event_id, user_id, event_type, ts, value), drops rows missing event_id or ts, writes to staged | | clean.py | Dedups on event_id, keeps only valid event types, converts timestamps to UTC ISO, formats value to 2 decimals | | metrics.py | Writes daily_metrics.csv, one row per day | ## Configuration (config.yaml) | Key | Default | Meaning | |-----|---------|---------| | paths | pulse/data/... | Where each stage reads and writes | | events.valid_types | page_view, signup, purchase, api_call | Event types clean.py keeps | | alerts.min_daily_events | 50 | Days under this get alert=LOW | ## Output columns (daily_metrics.csv) | Column | Meaning | |--------|---------| | day | UTC date | | events | Rows that survived cleaning that day | | active_users | Distinct user_id count | | total_value | Sum of value, 2 decimals | | alert | LOW when events is under 50, else empty | A LOW alert means the day had fewer than 50 cleaned events. It signals "look at this day", not "the pipeline failed" - see the how-to guide for diagnosing one. ## Project status Actively maintained as course material, 2026-07.
Build-along 3 of 3

The 30-second test ★ 6 min · pairs

Session 1 opened with three questions a newcomer asks of Pulse. The README's exit exam: can a fresh reader answer all three from the README alone, fast?

Swap screens with a partner (or close the README for ten minutes and return with fresh eyes).

Start a timer. Using ONLY the README, answer: How do I run it, and in what order? Which event types are valid? What does the LOW alert mean?

Score it: all three inside 30 seconds of scanning each is a pass. For any miss, note WHERE the reader looked first - that is where the answer belongs, regardless of where you put it.

Fix the misses by moving content up or renaming a heading - not by adding more prose. Scan failures are structure failures.

★ Milestone 1, shipped In Session 1 those three questions took minutes of code-reading and a trip through NOTES.txt. Now they take one scan of one page. That delta is the entire value of documentation, measured.
Homework

Try it yourself - this week ◐ 30-45 min total

Source material

Official sources covered

This session teaches the working content of these sources. What stays with the originals: makeareadme.com's full FAQ and history, and the Google style guide's exhaustive word-level entries.

✓makeareadme.com · the README templatePart 1 + Demos: section order, what to keep and skip, "too long beats too short"
✓Google style guide · Code samplesPart 2: runnable samples, why-not-what comments, expected output
✓Google style guide · PlaceholdersPart 2: capitalized italic code font, PULSE_RAW_DIR style
✓Write the Docs · beginner's guide, "what to include"Part 1 + Demo 2: the minimum viable doc set for a repo's front door
◐Microsoft style guide · Formatting developer textOverlaps Google's rules; skim for the differences if your org follows Microsoft style
Check yourself

Three questions before you go 🎯 ◐ 90 seconds

1 · Which part of a README decides whether the 30-second reader stays?

The scan lands on the top band and rarely goes deeper. Scope, non-scope and audience in the first paragraph is how the right reader stays and the wrong reader leaves happy.

2 · How should a replace-me value like a project ID appear in a doc?

Capitals plus italics visually separate "replace me" from "type me literally". In plain code font, readers paste the placeholder as-is and get a folder named PULSE_RAW_DIR.

3 · Why does the Pulse quickstart print "10, then 8, then a file path" in the README?

Every command gets its expected output so the reader has a checkpoint. A quickstart without output is a hope; with output it's a test the reader runs on their own setup.

Session 4 cheat sheet · pin this

Canonical orderName · Description · (Badges · Visuals) · Installation · Usage · Support · Roadmap · Contributing · Authors · License · Status.
Skip on purposeInternal pipeline: no badges, visuals, roadmap, license. Every skipped section is a decision, not an omission.
Description = 3 sentencesScope, non-scope, audience - straight from Session 1. The top band wins or loses the scan.
Copy-paste-verifyCommands exactly pasteable, each followed by expected output. 10, then 8, then the metrics path.
Three fonts, three meaningsCode font = literal. Bold = UI element. CAPS italic code = placeholder, replace me.
Example hygieneexample.com only, never real user data. Teaching data is designed: Pulse's dupe + invalid row exist to be filtered.
Links say where they goLink the destination's name, never "click here". Nouns, not verbs.
Pulse statusREADME shipped ✓ and 30-second tested. Next gap: nothing serves the on-call engineer at 2am - Session 5 fixes that.