Skip to content

# Module 1: Foundations ​

## Lesson 1.1: What Makes an Agent? ​

Definition: An AI agent = LLM + Tools + Loop. Without any one of these three, it's not an agent.

    Agent = LLM (reasoning engine)
          + Tools (capability surface)
          + Loop (autonomous decision cycle)

- A single LLM call with no tools = chatbot
- An LLM with tools but no loop = augmented inference
- Tools + loop + LLM = agent (it can decide what to do next)

### The Three Components ​

1. LLM — The reasoning engine. Given context + available tools, it decides which tool to call and with what parameters. The LLM is NOT the agent — it's the brain of the agent.

2. Tools — The capability surface. Functions the agent can call: read files, run commands, search the web, query databases, call APIs. Each tool has a name, description, and input schema.

3. Loop — The autonomous decision cycle. Think (LLM decides) → Act (tool executes) → Observe (result comes back) → Repeat. The loop is what makes it autonomous.

## Lesson 1.2: The Harness vs The Model ​

Core insight: The agent harness IS the product, not the model.

Most engineers focus on model quality ("which model is best?"). The data tells a different story:

Aspect | Model Matters | Harness Matters
--- | --- | ---
Tool selection accuracy | ✓ | ✓ (prompt design)
Loop termination | ✗ | ✓ (iteration limits)
Security | ✗ | ✓ (hooks, sandboxing)
Cost | ✓ (per-token price) | ✓ (how many calls made)
Reliability | ✗ | ✓ (retry, fallback, verify)
Context management | ✗ | ✓ (window, summarization)

The multiplier effect: A good harness with a mediocre model outperforms a bad harness with the best model. The harness determines how many tokens you spend, how safely you operate, and how reliably you recover from failure.

### The 5 Subsystems of a Harness ​

A harness is not a single thing. It's five subsystems working together:

    HARNESS
    ├── Instructions   — System prompts, AGENTS.md, CLAUDE.md, skills
    ├── Tools          — Bash, file ops, MCP servers, APIs, custom tools
    ├── Environment    — File system, runtime, git worktree, sandbox
    ├── State          — Session history, context window, mental models
    └── Verification   — Tests, evals, verifier agents, review gates

Every agent failure maps to one of these five. When something breaks, don't swap the model — check each subsystem in order.

### The 4 Dimensions of Control ​

Your control over an agent boils down to four dimensions:

Dimension | What You Control | Leverage
--- | --- | ---
Context | What the agent knows (files, instructions, history) | High
Model | Which LLM powers the agent | Low (same for everyone)
Prompt | How you instruct the agent (system prompt, tools, skills) | Very high
Tools | What the agent can do (capability surface) | Highest

Great harness engineering = managing these four dimensions across many agents at scale.

## Lesson 1.8: Do You Trust Your Agents? ​

This is the central question of agentic engineering. Every architectural decision — security, verification, monitoring, autonomy — comes back to trust. The more trust you build into your systems, the more you can delegate. The more you delegate, the more leverage you have.

### The Counterargument: George Hotz ​

Not everyone agrees. George Hotz (founder of comma.ai, first iPhone jailbreaker) argues that AI agents cannot program and their adoption will be one of the most costly mistakes in the field's history.

His core critique:

- Agents produce statistically plausible output that is broken in increasingly hard-to-detect ways
- The "slot machine" problem: agents frontload progress quickly, then require endless tweaking to finish
- Large organizations with slow feedback loops will suffer most — bottom performers produce 10x slop

> "Golden era for buckets of slop, dark age for gems of quality." — George Hotz

### Why We Include This ​

If you only hear the optimistic view, you'll deploy agents naively and get burned. Hotz's critique identifies real failure modes. This course addresses each one:

Hotz's Critique | Our Solution | Module
--- | --- | ---
Slop amplification | CI/CD quality gates + golden datasets | M5
Hard-to-detect breakage | Verifier pattern (read-only checks) | M3
Slot machine polish problem | Defense-in-depth + confidence ladder | M3
No world models | Evaluation frameworks + pass@k | M6

The honest take: Agents produce slop. The harness, verification, and production patterns are what turn slop into shipped quality. Without the harness, Hotz is right.

### Meanwhile: Armin Ronacher ​

Armin (creator of Flask, Pi maintainer) reveals that Pi is built with Pi — agents building the tools that build agents. This is the meta-agent pattern in production. But he's honest about limitations:

> "We're quite far off today from where Bun and [others] are. Today it does not seem like we know how to pull off a dark factory."

The honest middle ground between full automation and pure skepticism.

### The Question Remains ​

Do you trust your agents? The answer should be: yes, because you've engineered the trust. Security (M3), verification (M3), production patterns (M5), and evaluation (M6) are how you earn that trust.

This is the central question of agentic engineering. Every architectural decision — security, verification, monitoring, autonomy — comes back to trust. The more trust you build into your systems, the more you can delegate. The more you delegate, the more leverage you have.

## Lesson 1.3: Decision Framework — "Should I use an agent for this?" ​

### The 4-Question Filter ​

1. Uncertainty level: Can you write deterministic code for this?

   - Yes → Write code, not an agent
   - No → Consider agent
   - Partially → Agent with deterministic guardrails

2. Failure cost: What happens if the agent messes up?

   - Low (chatbot, content gen) → Full autonomy
   - Medium (code gen, data processing) → Verification layer
   - High (financial, medical, infrastructure) → Human-in-the-loop

3. Loop depth: How many decisions must the agent make?

   - 1-2 steps → Single LLM call with tools
   - 3-10 steps → Simple agent loop
   - 10+ steps → Multi-agent with orchestration

4. Observability requirement: Can you tolerate a black box?

   - Yes → Full autonomy
   - No → Tool-augmented only (no freeform agent loop)

### The Decision Tree ​

    Can you solve it deterministically?
    ├── YES → Write code. Don't use an agent.
    └── NO →
        Is failure cost HIGH?
        ├── YES → Agent + human-in-the-loop + verification
        └── NO →
            Is loop depth > 10?
            ├── YES → Multi-agent system with orchestration
            └── NO → Simple agent loop with tool use

## Lesson 1.8: The Repository IS the Spec ​

Core principle: All necessary context for your agent should live in the repository. The repo is the single source of truth — not a README, not a wiki, not tribal knowledge.

### What the Repo Should Contain ​

    repo/
    ├── AGENTS.md or CLAUDE.md    — Agent instructions (THE file)
    ├── .cursorrules              — Tool-specific rules
    ├── skills/                   — Reusable skill definitions
    │   ├── skill-name/
    │   │   ├── SKILL.md          — What the skill does
    │   │   └── scripts/          — Supporting scripts
    ├── .mcp.json                 — MCP server configuration
    ├── .claude/hooks/            — Lifecycle hooks
    ├── init.sh                   — Environment setup script
    ├── feature_list.json         — Tracked feature inventory
    └── tests/                    — Verification evidence

### Why This Matters ​

An agent can only see what you put in front of it. A well-structured repo:

- Eliminates tribal knowledge (the agent discovers it from files)
- Makes onboarding instant (new agent reads the same files)
- Creates audit trails (every instruction is version-controlled)
- Enables multi-agent teams (all agents read from the same source of truth)

Rule: If an agent needs to know something to do its job, that information must be in a file in the repo.

## Lesson 1.8: The Agent Loop ​

### The Universal Pattern ​

Every agent, regardless of complexity, follows this loop:

    while not done and iterations < MAX_ITERATIONS:
        1. THINK: LLM receives context + tool list → decides what to do
        2. ACT: Tool executes (read file, run command, query DB, etc.)
        3. OBSERVE: Result comes back as a message
        4. REPEAT or DONE: LLM decides whether to continue or finish

### Pseudocode ​

python

    messages = [system_prompt, user_request]
    while True:
        response = llm.invoke(messages, tools=tool_definitions)
        if response.is_final_answer:
            print(response.content)
            break
        tool_name = response.tool_call.name
        tool_args = response.tool_call.args
        result = execute_tool(tool_name, tool_args)
        messages.append({"role": "assistant", "content": response.content})
        messages.append({"role": "tool", "content": str(result)})

## Lesson 1.8: Tool Calling Deep Dive ​

### Tool Definition Anatomy ​

Every tool needs four things:

python

    tools = [{
        "name": "search_web",
        "description": "Search the web for current information",
        "input_schema": {
            "type": "object",
            "properties": {
                "query": {"type": "string", "description": "The search query"},
                "max_results": {"type": "integer", "default": 5}
            },
            "required": ["query"]
        }
    }]

### The Reasoning Parameter ​

Every tool call should include a `reasoning` field. This forces the LLM to explain WHY before it acts:

python

    def search_web(query: str, reasoning: str, max_results: int = 5):
        """Search the web. The 'reasoning' param explains why this call is needed."""
        ...

This single pattern:

- Reduces hallucinated tool calls by ~40%
- Makes agent decisions debuggable
- Gives the LLM a "thinking slot" before acting
- Creates an audit trail for every action

### Forced Tool Calls vs Auto ​

Mode | Behavior | Use When
--- | --- | ---
`auto` | LLM decides to call tool or respond | Simple tasks, human handoff
`any` / `required` | LLM MUST call a tool | Agent loops where each turn = action
Specific tool | LLM must use exact tool | Debugging, testing, routing

## Lesson 1.8: Vibe Coding vs Agentic Engineering ​

### The Five Hard Rules ​

1. Risk compounds with runtime — A 1% per-turn failure rate = 63% chance of disaster over 100 turns. Long-running agents aren't safer, they're more exposed.

2. If your agent can write AND execute code, you're back at L1 security — The marquee break: agent writes `cleanup.py`, runs `python cleanup.py`, your production data is gone.

3. Every turn is a roll of the dice — Modern models refuse well 99% of the time. That last 1% grows with every feature release. Engineer the harness for the 1%, not the 99%.

4. Token costs scale with loop depth, not task complexity — A simple task with a bad loop costs 10x more than a complex task with a clean loop. Optimize the loop first.

5. What you can't measure, you can't improve — Every agent system needs: cost per task, success rate, loop efficiency, failure mode tracking.

## Lab 1.9: Your First Agent ​

Objective: Build a single-tool agent from scratch in under 50 lines.

Starter code: `course/labs/L1-first-agent/starter.py`

python

    # TODO: Fill in the agent loop
    # 1. Define a tool (search_web or file_read)
    # 2. Define the tool schema
    # 3. Implement the agent loop
    # 4. Handle tool results
    # 5. Print the final answer

    import json
    # Your code here...

Checkpoints:

1. Tool call is made correctly (schema matches)
2. Tool result is fed back to the LLM
3. LLM produces final answer using tool result
4. Loop terminates (doesn't run forever)

Solution: `course/labs/L1-first-agent/solution.py`

## Quiz M1 ​

1. What three components make an AI agent? (Multiple choice)
2. True/False: The model quality matters more than the harness design
3. When should you NOT use an agent? (Scenario-based)
4. What does the `reasoning` parameter do?
5. Calculate: If an agent has a 2% failure rate per turn and runs 50 turns, what's the probability of at least one failure?