On this page

Chapter 1 of 11. No prerequisite. This is the mental model everything else in the course sits on top of: what a repo is for, and why the first question about any piece of work is whether one exists.

Ask a working developer what GitHub is for and you'll get "where the code lives." That answer is true and it is also the least useful part of the picture. Across roughly 40 repositories I run day to day, most of the value has nothing to do with where the code sits. It has to do with what else lives in the same place: the devlog that says why a decision was made, the roadmap that says what happens next, the issue thread that recorded an argument I'd otherwise have forgotten I won. Code is the smallest thing a repo holds. Memory is the rest of it.

This chapter is the mental model. Later chapters cover the mechanics, the CLI, branches, PRs, Actions. None of that mechanics matters if the underlying model is wrong, and the model is simpler than the tooling makes it look: one repo per concern, private by default with a public surface you choose on purpose, and the repo as the durable record of a project rather than a snapshot of its current state.

The first question about any work

Before I write a line of code, draft a design, or even commit to doing a piece of work at all, the question is: is there a repo for it. Not "should I write this down somewhere." Not "I'll remember." Is there a repo.

The question sounds trivial until you notice what it actually forces. A repo is not free to create in the sense that a note is free to create. It has a name, which means the thing has to be named. It has a visibility setting, which means someone has to decide, out loud, whether the world gets to see it. It has a place for a README, which means someone eventually has to say what the thing is for in a sentence a stranger could read. None of that happens to a folder on your desktop. All of it happens the moment you type gh repo create.

That's the leverage. The question "is there a repo for it" is doing the job a project-kickoff meeting does at a bigger company, except it costs one command and nobody has to book a room.

Public by default is not a default. It's a choice you skip

GitHub's own framing of visibility is exactly two sentences, and both matter more than they look: "Public repositories are accessible to everyone on the internet," and "Private repositories are only accessible to you, people you explicitly share access with, and, for organization repositories, certain organization members." Read that again and notice what it doesn't say. It doesn't say private is the default and public is the exception, or the other way round. It says both are available, and you pick.

GitHub is explicit that this is a decision, not a fallback: "When you create a repository, you can choose to make the repository public or private." Nothing about that sentence lets you skip the choice. There's no third state where you haven't decided yet and the platform decides for you.

In practice, most of the ~40 repos I run are private. Client work, in-progress tools, anything with an API key or a customer's data anywhere near it, scaffolding I'm not proud of yet: private, full stop, no debate. The public surface is deliberate and small: this site's own codebase, a handful of finished tools I want to point people at, the odd utility that's genuinely useful to somebody else and carries nothing sensitive. The split isn't "public unless I remember to lock it down." It's "private unless I've decided, on purpose, that this one earns an audience."

That ordering matters because the failure mode runs one direction. A private repo that should have been public costs you nothing but a missed opportunity to show your work. A public repo that should have been private costs you a leaked secret, an embarrassing early commit history, or a client's unfinished work sitting in a search index. Default to private. Promote to public as an explicit act, not a shrug.

A repo is memory, not a code drop

The second half of GitHub's own definition is the one people skip past: a repository is "a place where you can store your code, your files, and each file's revision history." Files, plural, not just source files. History, not just the current state. That's the official framing, and it's a bigger claim than "where the code lives."

flow · where work lives
Vertical flow: working directory feeds the staging area, which feeds the local repository, which pushes to the remote repository on GitHubworking directorystaging arealocal repositoryremote (GitHub)
Four places your work can be, and only the last one survives your laptop. Everything this chapter argues follows from wanting work in the bottom box.

I take that literally. Every repo I run past a first commit gets a docs/devlog.md: one entry per shipped change, what happened and why, in the repo's own words rather than mine reconstructing it later. This site's devlog didn't exist from day one. It was created deliberately, to mirror a convention I liked in another project, and when it landed I didn't start it empty. I went back and hand-backfilled eleven entries covering an entire prior phase of work, Blocks 1 through 8b, that had shipped with genuinely no record of it at all. Real changes, already live, and until that afternoon nothing anywhere said why any of them happened.

That backfill is the whole argument in one incident. The repo's memory only exists because someone decided it should. GitHub gives you the revision history for free, every commit, every diff, forever. It does not give you the why for free. Commit messages get close on a good day and nowhere near it on a bad one. A devlog entry is the deliberate, human-authored layer on top: not what changed, which git log already tells you, but why, which nothing tells you unless you wrote it down.

The same logic extends to a roadmap file: vision, decisions taken and rejected, the phased plan, updated as it happens rather than reconstructed from memory when someone asks. Code, devlog, roadmap, all in the same repo as the thing they describe. Not a wiki somewhere else, not a shared doc that drifts out of sync, not a Slack thread that scrolls away. The repo is where the project's memory lives because the repo is the one place that can't fall out of sync with itself.

When the model breaks: the wrong repo

The model earns its keep hardest at the edges, and one edge case makes the point better than the working cases do. I run a portfolio page on this site that turns finished client work into cards: a name, a stack, a one-line description of what it does. Building a new card is mechanical once the underlying repo exists, because the card is just a read of what's already there.

One of those cards went out wrong. The work in question was, from memory and a bit of dictation, "a supermarket rebuild." I went looking for the repo to card it, found a directory that matched on name alone, and shipped the card from it. It came down again within minutes: the repo I'd carded turned out to belong to an entirely different, deliberately unnamed project (a Medusa headless build) once I actually checked what was inside it. The real supermarket work is a separate project entirely, and matching a directory to a description pulled from memory isn't the same as confirming what's actually in it. The card had to be withdrawn the moment the mismatch surfaced.

That's the cost side of "is there a repo for it" made concrete, except here the failure isn't the absence of a repo, it's trusting a repo I never actually opened. The question isn't paranoia. It's the only thing standing between "I did this work" and "I can point at exactly where and when I did this work, and confirm it's the right where." Skip the confirmation and the wrong project can end up wearing another project's name in public, if only for a few minutes.

Directory names are not proof of anything

That incident carries a second lesson worth pulling out on its own, because it's easy to miss inside the story of the card getting withdrawn.

The lesson wasn't "check more carefully next time," though that's true. The lesson was that a directory's name is a label somebody typed once, under time pressure, and it is not evidence of what the project became. Repos drift from their names constantly. A folder called flash-ui shipped a card under that name straight from its README, and the README predated a rebrand months earlier that the spec history had already recorded: the product had been renamed months before, and nobody had gone back to tell the README. The card had to be corrected, and the correction came from the spec, not from anything a casual look at the repo would have surfaced.

Put those two together and you get a rule worth carrying past this site: a repo's directory name and its README are convenient, not authoritative. When a repo's identity actually matters, the source of truth is whatever tracks decisions over time (a devlog, a spec history, a changelog), never the label on the tin. The system of record is the repo's history, not its filename.

The system of record pays for itself at build time

None of this is bookkeeping for its own sake. The portfolio page mentioned above doesn't hand-count anything. The little counters in its navigation, "5 systems, 5 builds, 6 tools", are computed at build time from the same list of projects the cards are drawn from, via one function that walks the data once and derives every number from it. Nobody updates a count when a project ships. The count is a property of the repo list, recalculated automatically every time the site builds.

That's the payoff for treating repos as the system of record rather than a place code happens to live. Once the repo is the ground truth, everything downstream, cards, counts, changelists, can be derived rather than maintained. The alternative, a hand-kept spreadsheet of "what I've built," rots the moment you stop updating it, and you always stop updating it. A repo doesn't rot the same way, because the code, the devlog, and the roadmap are the thing you were doing anyway. The record is a side effect of the work rather than a second job on top of it.

The rule to carry forward

One repo per concern. Private until you've made a deliberate, out-loud decision to make it public. A devlog and a roadmap inside the repo, not beside it, because the repo is the only place guaranteed to stay in sync with itself. And before any new piece of work starts, one question, asked first: is there a repo for it. If the answer is no, that's not a detail to fix later. It's the reason the work will eventually be unverifiable, uncardable, or both.

The next chapter takes the mechanical half of this seriously: running that whole discipline from the terminal with gh, so that creating the repo, deciding its visibility, and starting its record are one habitual motion instead of three separate chores you talk yourself out of.

// EXERCISE

Audit one real project against the system-of-record test

Pick one piece of work you've done in the last month, anything you'd describe out loud as a project, and find its repo. If it has one, check whether its visibility was a decision you remember making or a default you never revisited, and check whether anything in the repo records why its last real change happened. If it has no repo, create one now: gh repo create, choose visibility deliberately, and add a docs/devlog.md with one real entry describing the most recent thing you did on it.

Expected behaviour
  • You can name the repo for the project and state, from memory or from checking, whether its visibility was a deliberate choice
  • The repo (new or existing) has a docs/devlog.md with at least one entry that states what changed and why, not just what changed
  • If the project had no repo, it has one now, created with an explicit --public or --private flag rather than accepting an unread prompt
  • You can say in one sentence why this project would or would not survive the supermarket test: could a stranger find and verify this work from the repo alone
gh repo create my-project --private --description "One real sentence"
mkdir -p docs
cat > docs/devlog.md <<'EOF'
# Devlog

## 2026-07-25 - init: repo created as system of record
Started tracking this project properly. Previous work existed
only in local files with no shared history.
EOF
git add docs/devlog.md
git commit -m "docs: start devlog as system of record"

PROVE IT Run `gh repo view <owner>/<repo> --json visibility,name,description` on the repo you audited or created. The output should show a visibility value you chose on purpose and a description that would mean something to someone who never saw you build it.

// CHECKPOINT — REPOS AS THE SYSTEM OF RECORD
multiple choice · auto-checked

According to GitHub's own documentation, what determines whether a new repository is public or private?

exact answer · auto-checked

In the chapter's own words, what's the one question that should come before any new piece of work?

open · self-checked

A portfolio card shipped, sourced from a repo directory that matched the work by name, and was withdrawn within minutes when the directory turned out to belong to a different project entirely, while the real work had no repo at all. Explain why the chapter treats this as a failure of the system of record rather than a minor cataloguing slip.

Show answer

Two failures stacked. The work itself had no repo, so it had no durable memory: no history, no description, nothing a stranger could check to confirm it happened, which is why no honest card could be written for it. And the card that DID ship was grounded in a name-match on a directory rather than a verified mapping between claim and source, so it described a different project's architecture. The chapter's model treats the repo as the system of record precisely to prevent both: work without a repo cannot be pointed to later, and claims not traced to their actual repo are fiction with confidence. Neither is a filing problem; both trace back to skipping the 'is there a repo for it, and is it THIS repo' question at the start.

↺ re-read: “When the model breaks: the repo that didn't exist

Sources

  • About repositories
    GitHub Docs
    Confirms the public/private visibility split, the deliberate-choice-at-creation framing, and the repo-as-durable-history definition this chapter's mental model is built on
    docs.github.com
Back to guide overview