← Back to Blog

Learning about GenAI (LLMs, Foundations, and Tooling) if I Were Starting From Zero

I’ve learned most of what I know about generative AI the messy way — curiosity, persistence, and a lot of rabbit holes. No curriculum, no structured path. That worked for me, but it’s not something I can hand someone and say “start here.”

A Slack thread got me thinking about it more seriously. It made me want to actually work through what a real starting point looks like: not just “try Claude,” but the mental models, the foundations, the boundaries of what these tools can and can’t do. I realized I didn’t have a clean, consolidated answer. The resources are out there — courses, articles, explainers, deep dives on every corner of the space. But there’s no clear pathway through it. No sense of what to read first, what to skip, what actually matters if you’re an engineer trying to work with these tools rather than research them from the ground up. The landscape is loud. There’s a lot of information, it moves fast, and what matters today can be outdated tomorrow. I’ve chased my share of clickbait in my own pursuit of understanding — finding the signal takes real effort.

So here’s what I actually know, organized for someone starting from zero. The building blocks — a mental model for what’s actually happening, a foundation for how to work with these tools, and a map of the landscape. What you do with it is up to you. There’s no single right way to work with LLMs.

One word of caution: be skeptical. Doubt the output. Fact-check. If you’re coding — test it, find the edge cases, look for the holes. You’ll learn something along the way, even from the mistakes.

Here’s where I’d start.


What’s actually happening inside an LLM

The first thing to understand is what an LLM actually is: a system trained to predict the most likely next token given everything before it. Not a search engine. Not a database. Much of what it can do, where it fails, and why it fails follows from that one mechanism.

The model doesn’t work in words. It works in tokens — subword units that don’t map to word boundaries the way you’d expect. Tokenization is the process that converts your text into those token units — the OpenAI tokenizer lets you see how your input gets split into tokens. Code tokenizes differently from prose. This matters in practice because context limits, API costs, and some edge-case behavior are all counted in tokens, not words.

The context window is everything the model can see at a given moment — its working memory. Think of it like a function that only knows what was passed in: no global state, no persistent memory across sessions unless you explicitly include it. Long conversations gradually degrade because earlier content falls out of the window. The model isn’t forgetting you — it never had access to anything outside what you gave it.

Hallucinations are the direct consequence of how generation works. The model doesn’t look up facts; it generates the most plausible continuation of your input based on patterns it learned during training. There’s no internal uncertainty signal — it produces confident-sounding text regardless of whether the underlying claim is accurate. This isn’t a bug being fixed. It’s structural. The right response isn’t distrust — it’s building a workflow that accounts for it.


The language of LLMs: prompt engineering

Prompting is an interface. Like learning a CLI or an API, it rewards the time you put into it. Output quality is heavily shaped by the clarity and specificity of your instructions — and the model won’t tell you when your prompt is the problem.

Context is the first lever. Give the model what it needs to do the job: what you’re building, what constraints exist, what format you want back. More relevant signal produces better output. This isn’t about writing long prompts — it’s about signal density. A short, focused prompt with the right context beats a long one full of noise.

Role framing shapes behavior. “You are a code reviewer focused on security vulnerabilities” produces a different response than “you are a helpful assistant.” In product interfaces like Claude.ai or ChatGPT, some of this is handled by the product’s system prompt. At the API level, you write it yourself. Even in conversational use, how you open a conversation frames everything that follows.

If you want a specific format or style, show it — one or two examples is often more effective than describing the structure you want. The model will pattern-match to your examples.

Specificity is consistently underestimated. Vague prompts produce vague output. “Write a function” and “Write a Ruby function that takes a string array and returns deduplicated sorted values, no external libraries” are not the same request. The more constrained and concrete your prompt, the closer the output will be to what you actually want.


The tooling landscape

Two companies are leading right now — Anthropic and OpenAI. Each has a general-purpose chat interface and an agentic coding tool. That’s the map.

Chat interfaces

Claude — Anthropic’s product. Strong at reasoning, writing, and code. Clean interface, free tier is genuinely capable. This is where I’d start if you’re opening your first AI tool — use it on a real problem, give it context, see how it responds.

ChatGPT — OpenAI’s product. The most widely used AI tool in the world. Solid across the board, has reasoning models for harder problems. If you already have an account here, stick with it and learn the tool you have.

Pick one and actually use it before adding more tools. The learning happens in use, not in switching.

Agentic coding tools

This is the category worth paying close attention to if you write code. These tools don’t just suggest — they read your files, write code, run commands, and work through multi-step tasks. You’re still directing and reviewing. But the work is theirs.

Claude Code — Anthropic’s agentic coding tool. Runs in your terminal. You give it a task in natural language — “add pagination to this endpoint,” “fix the failing test in checkout” — and it reads your codebase, plans, writes code, runs commands, and reports back. Available as a CLI, a VS Code extension, and a desktop app. It operates inside your actual project directory and asks when it’s uncertain. The difference from anything before it: the tool has autonomy — it doesn’t autocomplete a line, it reads, writes, runs, and observes until the task is done.

Codex — OpenAI’s equivalent. Same concept: give it a task, it executes. OpenAI has been iterating quickly on this and it’s worth following. Both Codex and Claude Code represent the frontier of what AI-assisted development currently looks like.

The agentic tools aren’t autopilots. The output still needs your attention. But if you’re an engineer who hasn’t tried one yet, put it on a real task and see what happens.


Build a working style

Mine is trust but verify. The trust part comes last. Before anything the agent wrote ships, I’ve read through it, run the tests, and worked the edge cases — manually and through code. The verify isn’t a glance. It’s the same rigor I’d bring to any pull request or task I’m responsible for. Trust is what I extend after doing that work, not a starting assumption.

Some engineers route nearly everything through AI — code, docs, debugging, drafts. Others use it selectively, for specific tasks where it’s earned a spot in the workflow. Both can work. What doesn’t work is passive use — feeding it a task and accepting the output without engaging critically with what came back.

The prompts you invest time in are a durable asset. The ones that work today will work next month, across different problems. Iterate on them, and save the ones that work — a prompt you’ve tuned for code review or test generation is a reusable tool. There’s also a useful feedback loop here: your prompts reflect how clearly you’ve thought about the problem. Vague thinking produces vague prompts, which produce vague output.

Some work is better without AI in the loop. First-principles reasoning, deep architectural decisions, building intuition in a domain you’re still learning — if you always outsource the hard thinking, you don’t build the mental model you need to evaluate the output. That’s not a moral argument. It’s practical: if you can’t judge whether the output is good, you can’t catch when it’s wrong.

The model will produce something that looks complete, sounds confident, and sometimes has a mistake buried in the middle. The cost of checking is lower than the cost of shipping something wrong. The tool generates; you own the output.


Building with AI: what’s actually happening

Using Claude or ChatGPT is one thing. Understanding what’s happening underneath changes how you use the tools — especially when you need to diagnose why the output is wrong. Two concepts worth knowing: RAG and agents. You’ve already been using both without necessarily naming them.

RAG (Retrieval-Augmented Generation)

The core problem: a model only knows what it was trained on, plus whatever you put in the context window. If you ask it about your codebase, your internal docs, or something that happened after its training cutoff, it doesn’t have that information.

RAG is how that gets solved. Before the model generates a response, the system searches an external source — a database, a set of documents, a codebase — pulls the most relevant pieces, and injects them into the context. The model then generates a response grounded in that retrieved content.

IBM’s RAG explainer is one of the clearer writeups on the concept.

You’ve already seen this in action:

  • When Claude or ChatGPT has web browsing enabled, they search first, retrieve relevant pages, then generate an answer from what they found. That’s RAG.
  • When an agentic tool like Claude Code or Codex reads your codebase before writing code, it’s pulling your actual context into the model’s window before generating anything. Same pattern.
  • Any AI tool that can “see” a document, a knowledge base, or a codebase is doing some version of this.

Knowing this changes how you think about context. The more relevant information in front of the model, the better the output — because it’s working with real signal, not only pattern-matching from training data.

Agents

A chat model takes a question and returns an answer. An agent takes a task and executes it.

The difference is the loop. An agent can: take an action, observe the result, decide what to do next, take another action, and keep going until the task is done or it hits a wall. It uses tools — code execution, file reads, web search — and iterates across steps rather than returning a single response.

Anthropic’s Building effective agents breaks down how these systems actually work.

Both Claude Code and Codex work this way:

  • Claude Code — you give it a task, it reads files, writes code, runs tests, observes the output, and loops. That’s an agent.
  • Codex — same structure. The model doesn’t hand you one answer; it works through the problem step by step.

This is why these tools can take on multi-step work that a chat interface can’t. A chat model stops after one response. An agent keeps going.


Spec-driven development

Writing the spec before you prompt is one of the most useful building blocks to bring into your AI workflow — and when you get into agentic tools, it becomes even more central.

The idea is straightforward: before you ask for code, write down what the code should do. The model fills in anything you leave ambiguous with its best guess, and its best guess is often wrong in subtle ways, not obvious ones. It looks right until it doesn’t.

Vague prompt:

“Add search to the posts endpoint.”

The model produces something. It works in the happy path. But it made assumptions — about case sensitivity, what fields to search, how to handle empty input, what to return when nothing matches, whether to use SQL or something else. You now have to audit all of those decisions.

Specific prompt:

“Add a case-insensitive search to GET /posts. Accept a q query param. Filter by title using SQL LIKE. Return a JSON array of matching posts sorted by date descending. Return an empty array (not 404) when nothing matches. No external search libraries.”

Same task. The second version produces output you can evaluate against what you wrote. Either it does what you described or it doesn’t.

What to put in a brief:

Before you prompt, write this down:

  • What it should do — the behavior, end to end
  • What it should NOT do — constraints, things to avoid
  • The stack and context — language, framework, patterns in the codebase it should follow
  • Edge cases you care about — empty input, missing data, boundary conditions
  • Output format — JSON shape, class name, file structure, whatever applies

Two to five lines of dense, specific description will outperform two vague paragraphs every time. The spec also doubles as your evaluation criteria — when the output comes back, you’re checking it against what you wrote, not just a feeling.

There’s another dimension worth naming: specs are the bridge between business intent and implementation. When you’re translating product requirements into technical work — with real acceptance criteria and edge cases, not just a high-level description — writing the spec is where that translation happens. The chain only holds if each step translates well. A clear business requirement can still produce a muddled technical brief if the person writing it lacks the technical context — and a muddled brief produces a muddled prompt regardless of how specific you try to be. Get good at each translation, and your work connects directly to what the user actually needs.

In agentic workflows, this goes further. When you’re working with Claude Code or Codex, specs don’t just live in a single prompt — they can be persistent. The CLAUDE.md file in your project, the skills you define, the project-level rules you configure — these are all specs in the same sense. You’re telling the agent how to behave across your entire codebase: what conventions to follow, what to avoid, how to handle recurring patterns. The agent reads them every time it runs. How clearly you’ve written those specs directly shapes the quality of the work it does.

If you can’t write the spec, you haven’t thought the problem through yet. That’s worth knowing before you hand it off.


Agentic setups and harnesses

An agentic tool without configuration is generic. It’ll do what you ask, but it has no idea how your project is structured, what conventions you follow, what to avoid, or what commands to run. A harness is the configuration layer that changes that — the persistent instructions, rules, and automated behaviors that make the agent work like someone who already knows your codebase.

Both Claude Code and Codex organize this into two levels: the project (lives in the repo, shared with the team) and the user level (lives on your machine, personal to you). Both layers run together; project config takes precedence when they conflict.

Here’s what the full configuration surface looks like for each. You don’t need all of it on day one — but knowing it exists changes how you think about what the agent can be told to do.

Claude Code

Project level

  • CLAUDE.md — a markdown file at the project root that Claude Code reads at the start of every session. Project context, coding conventions, what commands to run tests with, what to avoid. The onboarding doc for the agent. Can also live in subdirectories for more granular context.
  • Settings.claude/settings.json for project-scoped permissions and preferences.
  • Skills — reusable slash commands defined in .claude/skills/. Each skill is a directory with a SKILL.md file packaging instructions, scripts, and resources for a repeatable workflow. Checked into the repo so the whole team can use them.
  • Hooks — shell commands that run automatically before or after Claude Code actions. Auto-format after every file edit. Run lint before a commit. Fire a summary when the agent stops. Defined at the project level so they apply to everyone working in that repo.
  • Scripts — shell scripts the harness or hooks can invoke. Used in skills to wrap complex commands the agent should run reliably.
  • Sub-agents — Claude Code can spawn parallel agents to handle concurrent subtasks. A lead agent coordinates the work, assigns pieces to sub-agents, and merges the results. Enables multi-step parallelizable tasks that a single agent loop can’t do as efficiently.

User level

  • ~/.claude/CLAUDE.md — your personal global instructions. How you like to work, your preferred style, defaults you always want regardless of project.
  • ~/.claude/settings.json — global preferences, tool permissions, MCP server connections.
  • Personal skills — skills in ~/.claude/skills/ that follow you to every project. Not tied to any repo.
  • Personal hooks — automated behaviors you want in every session, everywhere.

Codex

Project level

  • AGENTS.md — Codex’s equivalent of CLAUDE.md. Lives at the project root; Codex reads it before starting any work. Can also live in subdirectories — Codex concatenates them from the root down, with files closer to your working directory taking precedence.
  • Config.codex/config.toml for project-scoped settings, approval policies, sandbox permissions, and MCP server integrations.
  • Skills — task-specific capability packages in .agents/skills/. Each skill is a directory with a SKILL.md file that packages instructions, scripts, and resources. Codex activates them explicitly (via /skills or $ prefix) or implicitly when the task matches the skill’s description.
  • Hooks — lifecycle hooks configured in config.toml. Supported events: PreToolUse, PostToolUse, PermissionRequest, SessionStart, and Stop. Same concept as Claude Code hooks, different config surface.
  • Sub-agents — Codex supports multi-agent workflows via spawn_agent, send_input, and resume_agent tools. Parallel agents handle concurrent subtasks, governed by nesting depth and thread limits.

User level

  • ~/.codex/config.toml — global configuration: model preferences, approval policies, sandbox settings, tool permissions.
  • $HOME/.agents/skills/ — personal skills that follow you across all projects.
  • AGENTS.override.md in the Codex home directory — a global instruction file that applies to every project, equivalent to ~/.claude/CLAUDE.md.

The pattern

The two tools use different file names and config formats, but the architecture is identical: project-level specs for the codebase, user-level specs for how you work. Skills package recurring workflows. Hooks automate what should always happen. Sub-agents parallelize larger jobs.

The investment is front-loaded. A well-configured harness runs every session without you having to ask. The agent that starts with full context about your project makes fewer wrong turns, asks fewer clarifying questions, and doesn’t need you to re-explain your conventions every session.


Where to start

You’ve read the guide. Before the sequence, one mindset shift worth making: when you work with an agentic tool, you’re not using software the way you use a text editor or a compiler. You’re directing an entity — setting the goal, delegating the work, reviewing the output, and deciding what happens next. Software Engineering at Google captures the underlying principle: give the assignment, let it fail, try again. The agent won’t learn from failure — but you will. Each iteration tightens the spec and sharpens how you direct. You’re the captain. The agent executes. Hold that framing and everything else in this guide clicks into place — the specs, the harness, the small commits, the tests. You’re not outsourcing your thinking. You’re directing with it.

Here’s the sequence.

1. Experiment with one tool. Pick Claude Code or Codex and bring it a real problem — a piece of code you’re stuck on, a feature you’ve been putting off, a test suite that doesn’t exist yet. Objects at rest stay at rest — don’t let that be you. Momentum builds the moment you start.

2. Write a spec before your next coding task. Even two sentences. Notice what changes in the output compared to a vague request. That gap is the lesson.

3. Commit before you hand off anything to an agentic tool. Before giving Claude Code or Codex a task on your codebase, commit your current state. Then make small, focused commits as work progresses — not one massive change at the end. Small commits are easy to review, easy to roll back, and leave a trail you can follow if something goes sideways. A large undifferentiated set of changes is hard to reason about and harder to undo.

4. Install an agentic tool on an existing project. Starting with something you already know gives you domain knowledge to make more informed decisions — you’ll catch things the agent gets wrong faster, and you’ll have better instincts for what to ask.

5. Write a CLAUDE.md or AGENTS.md. Start with three things: what the project is, the tech stack, and what to avoid. That’s enough to make a real difference in how the agent approaches your work.

6. If you’re coding: use TDD. Write tests before asking the AI to write the implementation. Make sure the tests are testing real behavior, not just structure. A test that passes without being meaningful is worse than no test — it creates false confidence. This matters especially with AI-generated code, where things can look right and fail at the edge.

The Beyoncé Rule from Software Engineering at Google applies directly: “If you liked it, then you shoulda put a test on it.” If you care about a behavior in your code, write a test for it. AI tools will change code. Tests are how you catch when something that mattered got broken.

7. Come back to the foundations after a week. The sections on context windows, hallucinations, and prompt engineering land differently once you’ve seen the behavior firsthand. The same goes for your harness files — CLAUDE.md, AGENTS.md, skills, hooks. Projects evolve, conventions shift, and what you wrote at the start won’t always reflect where the project is six months later. Revisit them periodically. A stale spec is just as misleading as no spec.

The tools will keep changing. New models, new products, new capabilities — that’s guaranteed. The mental models move slower: how context works, why specs matter, what agents can and can’t do. Invest in the understanding, not just the tools. The understanding transfers.


Closing thoughts

Things evolve — the tools, the landscape, and my own thinking. I’ll update this or write follow-ups when something needs reframing or when I find something that works better.

The thread running through all of it stays the same: you’re in charge. Not the model, not the agent. They execute on your direction — your specs, your harness, your judgment. The goal isn’t to stop thinking. It’s to get better at directing. Offload your thinking, and you’re just trusting the model’s best guess. You’re the captain — direct well, and the quality of your work compounds with every task.