8 Essential AI Agent Development Techniques from learn-claude-code

The learn-claude-code repository teaches eight progressive techniques for building autonomous Claude-based AI agents, including core agent loops, tool dispatch systems, task delegation, and context compression.

The shareAI-lab/learn-claude-code repository provides a step-by-step curriculum for AI agent development using Claude. Through six progressive scripts (s01 through s06), it demonstrates how to evolve a simple chat loop into a robust autonomous system with long-term memory, task delegation, and dynamic knowledge loading.

Core Agent Loop and Tool Dispatch Systems

Every autonomous agent in the repository builds upon a foundational interaction pattern that repeatedly sends message history to Claude, executes any requested tools, and feeds results back until the model stops calling tools.

The Basic Interaction Loop

In agents/s01_agent_loop.py, the core logic resides in a while-true loop at lines 66‑78 that creates a message, checks for tool_use blocks, executes them, and appends results to the conversation history. This pattern appears consistently across all six stages.

The minimal implementation from minimal-agent.py demonstrates this architecture in under 80 lines:

from anthropic import Anthropic
from pathlib import Path
import subprocess, os

client = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))
MODEL = os.getenv("MODEL_NAME", "claude-sonnet-4-20250514")
WORKDIR = Path.cwd()

TOOLS = [
    {"name": "bash", "description": "Run shell command",
     "input_schema": {"type": "object", "properties": {"command": {"type": "string"}}, "required": ["command"]}},
    {"name": "read_file", "description": "Read file", "input_schema": {"type": "object", "properties": {"path": {"type": "string"}}, "required": ["path"]}},
    {"name": "write_file", "description": "Write file", "input_schema": {"type": "object", "properties": {"path": {"type": "string"}, "content": {"type": "string"}}, "required": ["path", "content"]}},
]

def execute_tool(name, args):
    if name == "bash":
        r = subprocess.run(args["command"], shell=True, cwd=WORKDIR,
                           capture_output=True, text=True, timeout=60)
        return (r.stdout + r.stderr).strip() or "(empty)"
    if name == "read_file":
        return (WORKDIR / args["path"]).read_text()[:50000]
    if name == "write_file":
        p = WORKDIR / args["path"]
        p.parent.mkdir(parents=True, exist_ok=True)
        p.write_text(args["content"])
        return f"Wrote {len(args['content'])} bytes"
    return f"Unknown tool: {name}"

def agent(prompt, history=None):
    history = [] if history is None else history
    history.append({"role": "user", "content": prompt})
    while True:
        resp = client.messages.create(
            model=MODEL, system="You are a coding agent.", messages=history,
            tools=TOOLS, max_tokens=8000,
        )
        history.append({"role": "assistant", "content": resp.content})
        if resp.stop_reason != "tool_use":
            return "".join(b.text for b in resp.content if hasattr(b, "text"))
        results = []
        for block in resp.content:
            if block.type == "tool_use":
                out = execute_tool(block.name, block.input)
                results.append({"type": "tool_result", "tool_use_id": block.id, "content": out})
        history.append({"role": "user", "content": results})

Tool Handler Mapping

agents/s02_tool_use.py introduces a dispatch map pattern using the TOOL_HANDLERS dictionary at lines 94‑100. This structure routes the model’s tool_use calls to safe helper functions for bash execution, file I/O, and text editing. All file-access tools pass through safe_path() at lines 40‑45, which resolves paths against the working directory and rejects any traversal that escapes the repo sandbox.

Self-Tracking with TodoManager

Autonomous agents require structured planning capabilities. agents/s03_todo_write.py implements a TodoManager class at lines 51‑74 that exposes a todo tool registered at lines 45‑46. This allows the model to maintain a structured task list, mark progress, and receive reminders about pending work.

The tool validates that only one item carries in_progress status at a time, ensuring the agent maintains singular focus. When the model invokes the tool with a payload like the following, the handler updates the internal state and returns a human-readable markdown representation:

TOOL_HANDLERS["todo"] = lambda **kw: TODO.update(kw["items"])

# Example payload:

{
  "name": "todo",
  "input": {
    "items": [
      {"id": "1", "text": "Clone repository", "status": "completed"},
      {"id": "2", "text": "Run tests", "status": "in_progress"},
      {"id": "3", "text": "Write documentation", "status": "pending"}
    ]
  }
}

Sub-Agent Delegation for Parallel Processing

To handle complex workflows without polluting the parent context, agents/s04_subagent.py demonstrates task delegation via the run_subagent function at lines 15‑33. The parent agent registers a task tool at lines 36‑40 that spawns a fresh child agent with an empty message history but shared filesystem access.

The child runs the standard tool loop with only base tools (bash, read_file, write_file), then returns a concise text summary to the parent. This pattern isolates sub-tasks while maintaining workspace coherence:

if block.name == "task":
    desc = block.input.get("description", "subtask")
    print(f"> task ({desc}): {block.input['prompt'][:80]}")
    output = run_subagent(block.input["prompt"])   # runs a fresh loop

else:
    output = TOOL_HANDLERS[block.name](**block.input)

Dynamic Skill Loading Architecture

As agents grow complex, system prompts become unwieldy. agents/s05_skill_loading.py solves this through on-demand skill loading using the SkillLoader class initialized at lines 56‑63. The system prompt contains only skill names and brief descriptions generated by get_descriptions at lines 84‑96, while full markdown bodies remain externalized.

When the model requires domain expertise, it calls the load_skill tool registered at lines 70‑84, which invokes get_content at lines 98‑103 to retrieve the full skill file from the skills/ directory:


# Model requests:

{
  "name": "load_skill",
  "input": {"name": "pdf"}
}

# Handler returns full markdown content:

TOOL_HANDLERS["load_skill"] = lambda **kw: SKILL_LOADER.get_content(kw["name"])

This modular prompt engineering approach keeps the initial context lightweight while providing access to rich domain knowledge.

Context Compression and Memory Management

Long-running AI agent development sessions face token limit constraints. agents/s06_context_compact.py implements a three-layer compression pipeline to maintain session continuity.

Three-Layer Compression Strategy

The system provides micro-compact at lines 66‑94, which replaces old tool results with placeholders, and auto-compact at lines 96‑110, which saves the full transcript to .transcripts/ and requests a Claude-generated summary when token budgets are exceeded. Additionally, a manual compact tool registered at lines 71‑90 allows the model to trigger compression on demand with a specific focus parameter.

The compression workflow functions as follows:

  1. Micro-compact: Replace verbose tool outputs with (content saved to path) placeholders
  2. Auto-compact: Persist transcript to disk and summarize when estimate_tokens() (lines 61‑64) detects budget thresholds
  3. Manual compact: Model explicitly requests compression via tool call

# Model triggers manual compression:

{
  "name": "compact",
  "input": {"focus": "keep final test results"}
}

# Handler returns placeholder; loop then executes auto_compact(messages)

Token Budget Management

The estimate_tokens() function at lines 61‑64 provides a cheap approximation (≈4 characters per token) to determine when automatic compression should trigger, preventing runtime errors from context overflow.

Filesystem Safety and Sandboxing

All file operations throughout the repository enforce filesystem safety through the safe_path() helper (visible in agents/s02_tool_use.py at lines 40‑45). This function resolves relative paths against the working directory and raises exceptions for any path attempting directory traversal outside the designated sandbox.

Summary

  • Core Agent Loop: Implement a while-true cycle in agents/s01_agent_loop.py that exchanges messages with Claude until tool calls cease.
  • Tool Dispatch Map: Use a TOOL_HANDLERS dictionary in agents/s02_tool_use.py to route model requests to type-safe Python functions.
  • Task Tracking: Employ the TodoManager in agents/s03_todo_write.py to give the agent structured planning capabilities.
  • Sub-Agent Delegation: Spawn isolated child agents via run_subagent in agents/s04_subagent.py to parallelize work without context pollution.
  • Dynamic Skill Loading: Keep prompts concise using SkillLoader in agents/s05_skill_loading.py, loading full domain knowledge only when requested.
  • Context Compression: Maintain long sessions through micro-compact, auto-compact, and manual compact tools in agents/s06_context_compact.py.
  • Safety Primitives: Enforce workspace boundaries with safe_path() validators across all file-access tools.
  • Token Management: Monitor context budgets using estimate_tokens() to trigger compression before hitting API limits.

Frequently Asked Questions

Start with agents/s01_agent_loop.py to master the basic interaction pattern, then progress sequentially through s02 (tools), s03 (task tracking), s04 (delegation), s05 (skill loading), and finally s06 (context management). Each script builds upon the previous one, allowing you to compose a full-featured agent by layering capabilities.

How does the sub-agent pattern prevent context window exhaustion?

The run_subagent implementation in agents/s04_subagent.py creates a fresh sub_messages list for each child task. Because the child operates with an empty history and returns only a final summary, the parent context grows by a constant amount regardless of how many tool calls the child required to complete its work.

Can I use these patterns with other LLM providers besides Claude?

While the code relies on Anthropic's messages.create API and tool-use blocks, the architectural patterns—dispatch maps, todo tracking, sub-agent delegation, and context compression—are provider-agnostic. You would need to adapt the API client initialization and response parsing to match OpenAI, Gemini, or other providers' function-calling formats.

What safety measures prevent the agent from deleting my entire filesystem?

Every file-access tool routes through safe_path() (e.g., agents/s02_tool_use.py lines 40‑45), which resolves the target path against the configured WORKDIR and rejects any path containing .. or absolute references that escape the repository sandbox. Additionally, the bash tool includes a 60-second timeout to prevent runaway processes.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →