# Build From Scratch: 25 classic programs to build with an AI agent as your tutor, not your typist

A free guide by PaperChaseWebb for developers who use AI coding agents every day and want to understand the layers underneath them. The 25 classic "build your own" projects, sorted into three tiers, each with a v1 small enough to finish, what it teaches, the first test to write and what to leave out. Plus a tutor rules block that keeps Grok Bot, Claude Code, Codex or Hermes explaining and reviewing instead of writing the whole thing for you, six prompts, a five-milestone starter build (a small shell) and shell_check.py, a test script that checks each milestone for you. Plain .md. No signup, the whole thing is in this file.

Most "build your own X" lists are a wall of links. You pick something huge, follow a tutorial that hands you the code, and two weeks later you have a folder you copied and cannot explain. With an agent in the loop it gets worse: ask it to "build a database" and it will, in one go, and you learn nothing. This guide fixes the two things that decide whether a from-scratch build teaches you anything: a v1 you can actually finish, and an agent that is only allowed to teach.

## Contents

1. How to use this
2. The tutor rules block (paste first)
3. Approval steps
4. Tier one: build first
5. Tier two: strong second builds
6. Tier three: mastery builds
7. The milestone format
8. Starter build: a small shell in five milestones
9. shell_check.py, the milestone test script
10. The six prompts
11. Harness notes: Grok Bot, Claude Code, Codex, Hermes
12. When it goes wrong
13. Where this leads
14. What we looked at, and what we did differently
15. Sources
16. License


## 1. How to use this

1. **Pick one build.** Start in tier one unless you already finished a build from it. If you cannot pick, run prompt 10.1.
2. **Paste the tutor rules block** (section 2) at the top of every session for this build. It is the difference between learning and watching.
3. **Write the v1 scope on one page** using prompt 10.2. Everything not on the page is v2, by name.
4. **Work in milestones** (section 7). Each one ends with a working program and a passing test, so you can stop at any milestone and still have something that runs.
5. **Write the short write-up** at the end (prompt 10.6): what broke, and what the real tool was doing for you all along. That write-up is the part people read.

If you want a first build with tests already written, do the shell in section 8 and check it with the script in section 9.

## 2. The tutor rules block (paste first)

Paste this at the top of the session, or save it as the project rules file your agent reads on start (section 11 says where for each one).

```text
You are my tutor for a from-scratch learning build: [build name], v1 scope in SCOPE.md.
The point is that I understand every line. Rules:
1. Do not write implementation code into my files. You may write tests, test data and
   short examples of a concept that are not part of my project.
2. Before I write a piece, explain the idea in plain words, name the system calls or
   data structures involved, and point me to the real documentation (man pages, specs).
3. When I ask for help, give the smallest hint first. Give a bigger hint only if I ask
   again. Show code only when I type "show me", and then at most 15 lines.
4. Review my diffs like a strict senior engineer: bugs first, then edge cases, then style.
   Say which test would catch each bug.
5. Stay inside SCOPE.md. If I drift, say so and offer to add it to the v2 list.
6. Ask before running any command outside this project folder, installing anything,
   or using the network. Never push, publish or deploy.
7. At the end of each milestone, ask me to explain the milestone back to you in three
   sentences. If I cannot, we are not done.
```

Rule 1 is the whole product. If you want an agent to write the code, that is a fine thing to do, it is just a different job (see section 13).

## 3. Approval steps

The agent works inside your project folder and asks first for anything else. Five steps where you say yes or no:

| Step | The agent asks before | Why |
|---|---|---|
| Scope | Writing SCOPE.md | You own what v1 includes. |
| Tests | Adding or changing a test file | Tests are your contract; the agent proposes, you accept. |
| Commands | Running anything outside the project folder, or anything that installs, downloads or uses sudo | Low-level builds (allocators, file systems, kernels) can damage a machine if run in the wrong place. Use a VM or container for tier three. |
| Show me | Showing more than a hint | Keeps rule 3 honest. |
| Milestone done | Marking a milestone complete | Only after the test passes and you explained it back. |

## 4. Tier one: build first

Small enough to finish, and each one explains something your agents touch every day.

| Build | Smallest finishable v1 | What it teaches | First test to write | Leave out of v1 |
|---|---|---|---|---|
| Shell | Read a line, run a program, wait, then built-ins, pipes, redirects, background jobs | Processes, file descriptors, exit codes: the layer every coding agent runs commands through | `echo hello` prints hello | Scripting, tab completion, globbing |
| Scheduler | Run named jobs at fixed intervals from a text file, log each run, skip a run if the last one is still going | Time, queues, overlap, missed runs | A job set to every 2 seconds runs 3 times in 7 seconds | Cron syntax, time zones, distribution |
| Memory allocator | `my_malloc` and `my_free` over one big block with a free list | Pointers, fragmentation, alignment | Allocate, free, allocate again and get the same address back | Threads, size classes |
| Key-value database | `set`, `get`, `delete` over an append-only log file, rebuilt on start | Durability, indexes, why writes are hard | Set a key, restart, get the same value | SQL, transactions, concurrency |
| File system | A file system inside one file: create, write, read, list, delete | Blocks, inodes, what "saved" really means | Write 10 KB, reopen, read it back byte for byte | Permissions, journaling, mounting |
| Version control | `init`, `add`, `commit`, `log`, `checkout` with content-addressed objects | Hashing, trees, why history is cheap | Commit, change a file, checkout the commit, file is restored | Branches, merges, remotes |

## 5. Tier two: strong second builds

Bigger, still finishable in a v1, and each one sits under tools you already rely on.

| Build | Smallest finishable v1 | What it teaches | First test to write | Leave out of v1 |
|---|---|---|---|---|
| Web server | Serve static files over HTTP/1.1 with correct status codes | Sockets, the request and response format, keep-alive | `curl` gets the file and a 200; a missing file gets 404 | TLS, HTTP/2, a framework |
| Container runtime | Run one command in new namespaces with its own root folder (Linux, in a VM) | Isolation, how agent sandboxes actually work | Inside, `hostname` shows the new name and `ps` shows one process | Images, networking, cgroups beyond memory |
| Package manager | Install packages from a local folder with a manifest, resolve dependencies, write a lock file | Dependency graphs, version rules, supply chain risk | Installing A pulls in B and C in the right order | A registry, signatures |
| Network protocol | A tiny chat protocol over TCP with a written spec, framing and one error code | Framing, partial reads, versioning | Two clients exchange 1,000 messages with none lost | Encryption, discovery |
| Programming language | A calculator language with variables and `print`: scanner, parser, tree-walking evaluator | Grammar, parsing, scope | `x = 2 + 3 * 4; print x` prints 14 | Functions, types, a compiler |
| Compiler | Compile the calculator language to a stack machine you also write | Code generation, the gap between source and execution | Same program, same output as the evaluator | Optimization, real machine code |

## 6. Tier three: mastery builds

Long builds. Do them for depth, not speed, and always in a VM or container.

| Build | Sane v1 | Pairs with |
|---|---|---|
| Operating system | Boot in an emulator, print to screen, handle the keyboard | Scheduler, memory allocator |
| OS kernel in assembly | Same v1, by hand | Operating system |
| Virtual machine (bytecode) | A stack VM with 20 instructions and a disassembler | Programming language, compiler |
| CPU emulator | An emulator for a small documented chip (CHIP-8 is the usual start) | Virtual machine |
| Hypervisor | Run a tiny guest with the host's virtualization API | Container runtime |
| Browser | Fetch a page, parse a subset of HTML and CSS, lay out text and boxes | Web server |
| Game engine | A loop, sprites, input and collision, one small game made with it | GUI toolkit |
| Blockchain | A toy chain with blocks, hashes and proof of work, local only. Build a toy, not a token | Version control (same hashing idea) |
| Encryption algorithm | Implement a published cipher from its spec and match the official test vectors. Build to learn; never use hand-rolled crypto for anything real | Network protocol |
| Window manager | Tile windows on a Linux desktop with keyboard control | GUI toolkit |
| GUI toolkit | Buttons, labels and a layout box drawn on a canvas | Window manager, text editor |
| Text editor | Open, edit, save, undo, in the terminal | IDE |
| IDE | The text editor plus run, errors listed, jump to line | Text editor, language |

## 7. The milestone format

Every build uses the same page. Copy it into MILESTONES.md:

```text
Build: [name]            v1 scope: SCOPE.md
Milestone [n]: [one line]
Done when: [test name] passes and I can explain it in three sentences
New idea in this milestone: [one concept]
Read first: [man page, spec or chapter]
Not in this milestone: [named items]
Status: not started / in progress / done (date)
Write-up note: [one thing that surprised me]
```

Rules: four to six milestones for a v1. Each milestone adds one new idea. Each ends with a program that runs. If a milestone takes more than three sessions, split it.

## 8. Starter build: a small shell in five milestones

The shell is the best first build for anyone who works with coding agents, because every command an agent runs goes through one. Any language works; C, Rust, Go and Python all have the calls you need. One rule for every milestone: when input is not a terminal, print no prompt, so the test script can read your output.

| Milestone | What you add | Read first | Checked by |
|---|---|---|---|
| 1. Prompt and run | Read a line, split it into words, start the program, wait for it, report errors for unknown commands and keep going, ignore blank lines | `fork`, `exec` and `wait` man pages, or your language's process module | `shell_check.py ... --upto 1` |
| 2. Built-ins | `cd`, `exit`, `history`. Learn why `cd` cannot be an outside program | `chdir` man page | `--upto 2` |
| 3. Pipes and redirects | Pipes between any number of commands, then `>`, `>>` and `<` | `pipe` and `dup2` man pages | `--upto 3` |
| 4. Background jobs | `cmd &` returns at once; `jobs` lists what is running | `waitpid` with no-hang, signals overview | `--upto 4` |
| 5. Write-up | One page: what broke, and what the shell you use every day was doing for you invisibly | Your MILESTONES.md notes | You, and prompt 10.6 |

Quoting: the checks use simple single quotes in two places (`printf '%s-%s\n' a b` and `sh -c 'sleep 1; echo late'`). Handle single-quoted words as one argument in milestone 1. Full quoting rules are v2.

v2 list, by name: `$?` and variables, `&&` and `||`, globbing, tab completion, a config file, `fg` and job numbers, signal handling for Ctrl-C.

## 9. shell_check.py, the milestone test script

Save this as `shell_check.py` next to your project. It feeds lines to your shell on stdin, runs each case in a fresh temporary folder it deletes afterwards, and prints PASS or FAIL per check. It does not touch your project files. Python 3.8 or newer, no packages, Linux or macOS.

Run it with the command that starts your shell:

```text
python3 shell_check.py ./mysh --upto 1
python3 shell_check.py "python3 mysh.py" --upto 3
```

```python
#!/usr/bin/env python3
"""shell_check.py: milestone checks for a from-scratch shell.

Usage: python3 shell_check.py "<command that starts your shell>" [--upto N]
Example: python3 shell_check.py "./mysh" --upto 3

Each case feeds lines to your shell on stdin (not a terminal, so your shell
should print no prompt), runs it inside a fresh temp folder, and checks what
comes back. Read-only toward your project: it only writes inside the temp
folder it creates and deletes. Python 3.8+, no packages."""
import os, shlex, subprocess, sys, tempfile, shutil

CASES = [
 # (milestone, name, stdin script, check kind, expected)
 (1, "runs an external command", "echo hello\n", "lines", ["hello"]),
 (1, "runs commands with arguments", "printf '%s-%s\\n' a b\n", "lines", ["a-b"]),
 (1, "survives an unknown command", "nosuchcmd_pc_xyz\necho after\n", "lines", ["after"]),
 (1, "blank lines are ignored", "\n\necho ok\n", "lines", ["ok"]),
 (2, "cd changes folder for later commands", "mkdir sub\ncd sub\npwd\n", "endswith", "/sub"),
 (2, "exit stops reading input", "echo before\nexit\necho nope\n", "lines", ["before"]),
 (2, "history lists earlier commands", "echo one\nhistory\n", "contains", "echo one"),
 (3, "two-stage pipe", "echo hello | tr a-z A-Z\n", "lines", ["HELLO"]),
 (3, "three-stage pipe", "seq 5 | sort -r | head -n 2\n", "lines", ["5", "4"]),
 (3, "output redirect overwrites", "echo first > out.txt\necho second > out.txt\ncat out.txt\n", "lines", ["second"]),
 (3, "append redirect", "echo a > out.txt\necho b >> out.txt\ncat out.txt\n", "lines", ["a", "b"]),
 (3, "input redirect", "echo shout > in.txt\ntr a-z A-Z < in.txt\n", "lines", ["SHOUT"]),
 (4, "background job does not block", "sh -c 'sleep 1; echo late' &\necho early\nsleep 2\n", "lines", ["early", "late"]),
 (4, "jobs lists the background job", "sleep 2 &\njobs\n", "contains", "sleep"),
]

def run(cmd, script):
    d = tempfile.mkdtemp(prefix="shell_check_")
    try:
        p = subprocess.run(shlex.split(cmd), input=script, capture_output=True, text=True, cwd=d, timeout=10)
        return p.stdout, p.returncode
    except subprocess.TimeoutExpired:
        return None, None
    finally:
        shutil.rmtree(d, ignore_errors=True)

def ok(kind, exp, out):
    lines = [l for l in out.splitlines() if l.strip()]
    if kind == "lines": return lines == exp
    if kind == "contains": return exp in out
    if kind == "endswith": return bool(lines) and lines[-1].endswith(exp)
    return False

def main():
    if len(sys.argv) < 2:
        print(__doc__); return 2
    cmd = os.path.abspath(sys.argv[1]) if os.path.exists(sys.argv[1]) else sys.argv[1]
    upto = 4
    if "--upto" in sys.argv: upto = int(sys.argv[sys.argv.index("--upto") + 1])
    fails = 0
    for m, name, script, kind, exp in CASES:
        if m > upto: continue
        out, rc = run(cmd, script)
        good = out is not None and ok(kind, exp, out)
        fails += not good
        why = "" if good else ("  (timed out)" if out is None else f"  (got: {out.strip()[:80]!r})")
        print(f"M{m} {'PASS' if good else 'FAIL'}  {name}{why}")
    print(f"{fails} failing check(s) up to milestone {upto}")
    return 1 if fails else 0

if __name__ == "__main__":
    sys.exit(main())
```

How we tested it: on 2026-10-27 we wrote our own small reference shell (not included, so you build yours) and ran the script against it. It passed all 14 checks. With pipes broken on purpose, the two pipe checks failed and nothing else did. With background jobs broken on purpose, the two milestone 4 checks failed and nothing else did. Running it against non-interactive bash fails only the history check, which is expected: bash keeps no history when it reads from a script.

## 10. The six prompts

Each prompt assumes the tutor rules block from section 2 is already loaded.

### 10.1 Pick a build

```text
Help me pick one build from the Build From Scratch tiers. Ask me five questions, one at
a time: languages I know, how many hours a week I have, what tools I use daily, what I
want to understand better, and whether I can use a VM. Then recommend one build and one
backup, with one sentence each on why. Do not start the build.
```

### 10.2 Write the v1 scope

```text
We are building [build]. Interview me and draft SCOPE.md: what v1 does in five bullets
or fewer, what it will not do (named), the language, and how I will know v1 is done.
Show me the draft and wait for my yes before writing the file.
```

### 10.3 Plan the milestones

```text
Using SCOPE.md and the milestone format in this guide, propose four to six milestones.
Each adds one new idea and ends with something that runs. For each, write the first
test as a test file I can run, and list what to read first. Show the plan, wait for my
yes, then write MILESTONES.md and the test files only.
```

### 10.4 Teach before I code

```text
I am starting milestone [n]. Explain the one new idea in plain words, the system calls
or data structures involved and the most common mistake people make with it. Point me
to the real documentation. Then stop. Do not write my code.
```

### 10.5 Review my diff

```text
Review my changes since the last commit. List bugs first, then edge cases, then style,
each with the line and which test would catch it. If a test is missing, propose it and
wait for my yes. Do not fix the code yourself.
```

### 10.6 Write the write-up

```text
Milestones done. Using MILESTONES.md, my commit messages and what I tell you, help me
draft a one-page write-up: what I built, the three things that broke and why, and what
the real tool does that I never noticed before. My words, your edits. Keep claims to
what the tests show.
```

## 11. Harness notes: Grok Bot, Claude Code, Codex, Hermes

| Agent | Where the tutor rules go | Notes |
|---|---|---|
| Grok Bot | Save the rules block as a skill, or paste it at the start of the chat | Works well for the explain and review prompts. Keep the build on your own machine; paste diffs or file contents for review. |
| Claude Code | `CLAUDE.md` in the project folder | Keep permission prompts on for commands outside the folder. Ask it to run `shell_check.py` and report, not to fix. |
| Codex | `AGENTS.md` in the project folder | Use the approval mode that asks before running commands. Same "report, do not fix" line. |
| Hermes | Its project rules or system prompt file | If you run it on a local model, prompts 10.4 and 10.5 work best with the file contents pasted in. |

All four: if the agent starts writing implementation code, reply "rule 1" and it should stop and switch to a hint.

## 12. When it goes wrong

| What happens | Why | Fix |
|---|---|---|
| The agent writes the whole thing | The rules block was not loaded, or the request was "build X" | Reload section 2. Ask for explanations and reviews, not builds. |
| Week three, still no working program | v1 too big | Cut SCOPE.md to the first two milestones. Add one idea at a time. |
| Tests pass but you cannot explain the code | You took too many "show me" answers | Delete the milestone's code and rewrite it from your notes. It goes faster than you expect. |
| The build damaged your setup | Low-level work run on your main machine | Tier two containers and all of tier three go in a VM. |
| You lose interest | The build has nothing to do with your work | Pick from tier one by what you touch every day. |

## 13. Where this leads

- If you want agents to write production code well, not teach you, the [Vibe Coding with AI Agents pack](https://paperchasewebb.ai/bots/marketplace/items/vibe-coding-with-ai-agents/) ($39) covers that job: handoffs, review, testing and rules for Claude Code and Codex.
- If you run a team or an agency and want AI agents working on real workflows with approvals and owners, start with the free [Agent Readiness Self-Check](https://paperchasewebb.ai/bots/marketplace/items/agent-readiness-self-check-score-one-workflow-free/). When you would rather have it done for you, the $5,000 Install sprint is on the paperchasewebb.ai homepage (Book a call).

## 14. What we looked at, and what we did differently

We read the popular free lists and paid courses for "build your own" projects before writing this. The large community link lists (for example codecrafters-io/build-your-own-x on GitHub) are an excellent index but give no order, no scope and no tests. Paid challenge platforms (CodeCrafters) do have tests, but cover a handful of builds and are not written for learning alongside an AI agent. Long-form books like Crafting Interpreters are the gold standard for one build each. Short shell tutorials (Stephen Brennan's "Write a Shell in C") are a good first read for milestone 1.

What we did differently: one sorted list instead of a link dump; a finishable v1 and a first test for every build; the tutor rules block and approval steps so an agent teaches instead of typing; and a working test script for the starter build, tested against a reference and against planted faults. We did not copy any of them. Read them; they are good.

## 15. Sources

- The 25-build list: Instagram reel by Samuel Márquez (@sarthenaymm), 2026-10-11, https://www.instagram.com/reel/DeYh50PuV79/ (the list only; tiers, scopes and tests are ours).
- Shell milestone plan: our own build spec, rewritten for this guide.
- Looked at: https://github.com/codecrafters-io/build-your-own-x, https://codecrafters.io, https://craftinginterpreters.com, https://brennan.io/2015/01/16/write-a-shell-in-c/

## 16. License

Free for personal and commercial use, including teaching and client training. Do not resell or republish this file. shell_check.py may be copied into your own projects.

Version 1.0, 2026-10-27. Last tested: shell_check.py run against a reference shell and planted faults on 2026-10-27, as described in section 9. The prompts were walked through as a design check, not a study.
