The Curriculum / Reader / Agent Architectures
LEVEL 2 · INTERMEDIATE · INDIVIDUAL TRACK

Agent Architectures

This page compiles 4 files from the repository, verbatim, in reading order. The living version: this folder on GitHub.

level-2-intermediate/individual/01-agent-architectures/README.md

Agent Architectures

An agent is not a chatbot with a tool list. It is a controlled loop: observe state, choose an action, use a tool, inspect the result, and stop under explicit rules. Level 2 starts by choosing that loop deliberately. The wrong architecture creates expensive, flaky behavior that no prompt rewrite will fix.

Use the smallest loop that can complete the job. A lease clause extractor is mostly a structured extraction workflow with narrow tools; it does not need autonomous planning. A Deal Leverage diligence assistant may need a plan because a data room contains uneven documents and missing evidence. Tenant triage needs a router first, then deterministic policy checks, then a drafting model. Treat architecture as risk allocation: where can the model decide, where must software decide, and where must Adam approve?

Every agent in this program has five boundaries: an input contract, an allowed tool set, a state model, stop conditions, and an audit trace. Put business rules in code or query constraints; reserve the model for ambiguity, language, and prioritization. A good agent can explain which documents it read, which tools it called, what it believes, and why it escalated.

Read the pattern notes, then use the decision guide before building. Your default should be a router plus one narrow worker, not a committee of agents talking to each other.

In this module

Build standard: typed inputs and outputs, idempotent tools, explicit retries, a small eval set before production, and a kill path for every side effect.

level-2-intermediate/individual/01-agent-architectures/agent-patterns.md

Four Agent Patterns That Matter

ReAct: reason, act, observe

ReAct alternates a short decision with a tool call and an observation. It fits tasks where the next action depends on evidence: locate the current lease, retrieve a clause, compare it to a property rule, then request clarification if the dates conflict. Keep the action vocabulary tiny. The model should choose search_leases, get_clause, create_review_task, or stop, not arbitrary SQL. Log each turn as a trace. Cap turns at 4–8; more turns usually mean the tool contract is weak.

Plan–Execute

The planner produces a bounded checklist, and workers execute each item without rewriting the plan on every turn. Use it for Deal Leverage diligence: inventory documents, extract borrower terms, verify insurance, score missing items, draft the checklist. Persist the plan so a failed document can be retried independently. Plans are useful when completeness matters more than conversational agility. Validate the plan schema before execution and allow only approved task types.

Reflection

A worker drafts an answer; a critic checks it against requirements; a repair pass fixes concrete defects. Reflection works for high-value writing and structured extraction where an answer can be inspected. For example, require the critic to identify unsupported lease fields, impossible dates, and missing citations. Do not ask it “is this good?” Give it a rubric and source IDs. One review pass is usually enough; endless self-review burns tokens and can amplify an initial mistake.

Router

A router classifies the request and sends it to a specialized path. OTB tenant communication should route maintenance emergencies, payment questions, lease requests, complaints, and general inquiries differently. Use deterministic rules for obvious signals (fire, gas, lockout) before an LLM router. The router returns a label, confidence, and reason—not prose. Low-confidence or high-risk labels go to a human queue.

These patterns compose, but composition is not maturity. Start with one pattern, measure it, then add complexity only when an eval exposes a real gap.

level-2-intermediate/individual/01-agent-architectures/agents-are-folders.md

Agents are folders

Credit: this framing comes from Jake Van Clief and David McDermott, whose 2026 paper Interpretable Context Methodology (ICM): Folder Structure as Agentic Architecture formalizes what a lot of practitioners had converged on independently. Van Clief's video series and Substack (Clief Notes) walk through it in accessible terms. The community has largely picked this up as "agents are folders" — a compressed slogan for a real idea.

An AI agent is not a running process. It's a folder of markdown files that a model reads when you point it at them. The model is interchangeable. The folder is the asset.

Everything else — frameworks, orchestration code, agent SDKs, multi-agent choreography — is optional plumbing built on top of that primitive.

Why this framing matters

If you believe "an agent is a running LangChain graph," then: - You lock yourself into one framework - You have to redeploy to change behavior - The agent dies when the process dies - Non-programmers can't touch it - Version control means Git-diffing Python - Handoff between agents means serializing state through code

If you believe "an agent is a folder," then: - The agent is a plain-text asset in Git - Behavior changes are pull requests against markdown - The runtime (Claude, GPT, Gemini, Grok, a local model) is interchangeable — pick per task - Non-programmers can read, review, and propose changes - Handoff between agents is: this folder's output directory is that folder's input directory - The whole thing is portable, forkable, and inspectable

The 4 repos in this program are structured this way on purpose. Each has a small amount of TypeScript that hosts a tool surface, and the actual agent — the identity, the rules, the workflow — lives in markdown inside the repo.

The same agent, four ways

Here's a maintenance-triage agent expressed in four different runtimes. Same folder, same content, different host.

1. As a Claude Skill (this program's repo)

support-triage-agent/
├── skills/
│   └── triage/
│       ├── SKILL.md         ← frontmatter + instructions
│       ├── priority-rules.md
│       └── examples/
│           ├── p1.md
│           ├── p2.md
│           └── p3.md
├── src/
│   └── tools.ts             ← draft_response, search_kb (no send)
└── README.md

skills/triage/SKILL.md:

---
name: triage
description: Classify support tickets and draft responses. Use when a new ticket arrives.
---

You are a support triage agent for a property-management company.

## Priority rules
See `priority-rules.md`. P1 always includes: no heat, no water, gas leak, fire, security.

## Workflow
1. Read the incoming ticket
2. Classify priority (P1/P2/P3) using `priority-rules.md`
3. Draft a response using tone from `examples/`
4. Call `draft_response({ticket_id, priority, message})`
5. Never call a send tool — you don't have one

## Non-goals
- Never contact a tenant directly
- Never promise repair timelines you can't verify

The Claude Skills runtime loads SKILL.md on demand. priority-rules.md and examples/ are pulled in when referenced.

2. As a Claude Code subagent

your-project/
├── .claude/
│   ├── CLAUDE.md              ← project-wide identity
│   ├── agents/
│   │   └── triage.md          ← the agent
│   └── commands/
│       └── triage-inbox.md    ← slash command that invokes it
├── docs/priority-rules.md
└── src/

.claude/agents/triage.md:

---
name: triage
description: Support-ticket triage. Auto-invoke when I ask about tickets.
tools: [Read, Grep, Write]
model: claude-sonnet-4
---

You are a support triage agent...

(same body as the Claude Skill above — the content moves, the frontmatter changes)

Claude Code discovers the file via the .claude/agents/ convention. Same content, wrapped in Claude-Code-specific frontmatter.

3. As an OpenAI Assistant

support-triage-agent/
├── agent-config/
│   ├── system-prompt.md       ← same content, without frontmatter
│   ├── tools.json             ← OpenAI function schemas
│   └── deploy.ts              ← creates or updates the Assistant
└── src/
    └── tools.ts               ← same tool implementations

agent-config/deploy.ts:

import OpenAI from 'openai';
import { readFile } from 'node:fs/promises';

const client = new OpenAI();
const instructions = await readFile('./agent-config/system-prompt.md', 'utf8');
const tools = JSON.parse(await readFile('./agent-config/tools.json', 'utf8'));

await client.beta.assistants.create({
  name: 'triage',
  instructions,
  tools,
  model: 'gpt-4o-2024-11',
});

Same markdown, different runtime, wrapped in an SDK call. The system-prompt.md is the agent. deploy.ts is deployment plumbing you write once.

4. As a Perplexity Computer custom skill

~/perplexity-skills/triage/
├── SKILL.md
├── priority-rules.md
└── examples/

SKILL.md:

---
name: triage
description: Support triage for property-management tickets. Use when asked to triage a support inbox or classify a ticket.
---

You are a support triage agent...

(same body again)

Uploaded via save_custom_skill. Same content once more.

What actually changes between the four?

Field Claude Skills Claude Code OpenAI Assistant Perplexity Skill
Body of the instructions Identical Identical Identical Identical
Frontmatter format name + description name + description + tools + model none — sent as JSON to API name + description
How the runtime finds it User invokes via slash / natural language Auto-invoked from .claude/agents/ Fetched from OpenAI dashboard Auto-invoked when description matches
Where tools are defined Host codebase (MCP or in-repo) tools: list references built-ins tools.json Host codebase or connectors
How you edit it Edit markdown, restart Edit markdown, next turn Edit markdown, redeploy Edit markdown, upload

Everything that matters is the same. The persistent asset — the thing that captures the agent's actual behavior — is the markdown body. Everything else is runtime tax.

Consequences

1. Don't overinvest in one runtime. If your agent is a folder, migrating from Assistants API to Claude Skills to Perplexity is a ~30-minute exercise per agent. If your agent is a LangGraph, migration is a rewrite.

2. Version control your agents in Git, not in a vendor dashboard. The dashboard is a cache. Git is the source of truth. If the vendor deletes your agent tomorrow, you clone your repo and redeploy.

3. Design for composition, not for cleverness. The most interesting agents in this program are the ones that hand off structured data to each other (see module 13 — combine two agents). That composition works because each agent is a folder with an input contract and an output contract, not because there's a fancy multi-agent framework wiring them together.

4. Read a stranger's agent by reading their folder. No debugger, no dashboard, no framework knowledge required. cd in, cat the markdown, understand the agent. This is a form of literacy the whole industry underweights.

Where this framing gets tested

Van Clief and McDermott's paper explicitly notes that ICM is best for sequential workflows where a human reviews between stages. When you need parallel agents coordinating in real time with shared mutable state, filesystem-as-orchestrator gets awkward and you probably do want a framework.

But most real-world agent workflows — the ones this program teaches — are sequential with human review. That's the sweet spot. Ninety percent of the professional AI systems being deployed today are shaped like: input → agent stage 1 → human review → agent stage 2 → human review → output. For that shape, the folder IS the framework.

Read more

level-2-intermediate/individual/01-agent-architectures/when-to-use-what.md

When to Use Which Architecture

Choose from the failure mode, not from what looks impressive in a demo.

Situation Default architecture Why Do not use
Extract named lease fields from known documents Deterministic pipeline plus Reflection Schema and citations are inspectable Open-ended ReAct
Answer a lease question with document evidence ReAct with retrieval Each result determines the next lookup Multi-agent debate
Build a diligence checklist from an uneven data room Plan–Execute Completeness and resumability matter A single massive prompt
Triage incoming tenant messages Router plus policy rules Classification and escalation are the real job An autonomous agent with write access
Produce a human-reviewed owner update Draft plus Reflection Tone and completeness benefit from a critic Tool-heavy agent loop

Use a workflow, not an agent, when the path is known: nightly lease ingestion, embedding generation, invoice reminders, and scheduled reindexing should be queues and functions. The model can classify or extract inside the workflow, but it should not invent the sequence.

Use ReAct when the agent must discover which evidence is relevant. Make every tool narrow and read-only by default. If a tool can change property, money, tenant records, or a deal stage, make it return a proposal first. A separate approval action carries the side effect.

Use Plan–Execute when work has a finite checklist and can survive partial completion. Require each task to declare its inputs, expected artifact, and dependency. Do not let execution create new task classes.

Use Reflection only when the review can reference a concrete rubric. “Review yourself” is theater. “Flag every claim lacking a lease page citation; validate currency and date formats; return pass or a repair list” is useful.

The operating rule: deterministic software owns policy; models own interpretation; humans own irreversible judgment.

← Level 2 at a glance Build Your First Agent: Lease Clause Extractor →