# Building AI Agents

> Guide for building AI agents from scratch with tool use, agentic loops, and LLM APIs. Includes nanocode as a complete working example showing how to build a minimal Claude Code alternative in 270 lines.

- Skill: `createskyblue/building-ai-agents` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add createskyblue/building-ai-agents`
- Raw SKILL.md: https://api.skillmd.com/api/skills/createskyblue/building-ai-agents/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: createskyblue (https://skillmd.com/u/createskyblue)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/createskyblue/building-ai-agents

---


# Building AI Agents

Complete guide for creating AI agents with tool-use capabilities from scratch.

## When to Use

- Building new AI agents or coding assistants
- Implementing agentic loops with tool calling
- Learning agent architecture patterns
- Creating Claude API integrations

## Core Architecture

Every AI agent needs **four layers**:

```
┌─────────────────────────────────────────┐
│  1. Tool Definition Layer              │  Define what tools exist
└─────────────────────────────────────────┘
                 ↓
┌─────────────────────────────────────────┐
│  2. Tool Implementation Layer         │  Implement tool logic
└─────────────────────────────────────────┘
                 ↓
┌─────────────────────────────────────────┐
│  3. Schema Generation Layer           │  Convert to API format
└─────────────────────────────────────────┘
                 ↓
┌─────────────────────────────────────────┐
│  4. Agentic Loop Layer               │  Execute until complete
└─────────────────────────────────────────┘
```

## Quick Start

### Minimal Template (30 lines)

```python
import json, urllib.request

TOOLS = {
    "echo": (
        "Repeat input back",
        {"text": "string"},
        lambda args: args["text"],
    ),
}

def run_tool(name, args):
    return TOOLS[name][2](args)

def make_schema():
    return [{
        "name": name,
        "description": desc,
        "input_schema": {
            "type": "object",
            "properties": {
                k: {"type": v.rstrip("?").replace("number", "integer")}
                for k, v in params.items()
            },
            "required": [k for k, v in params.items() if not v.endswith("?")],
        }
    } for name, (desc, params, _) in TOOLS.items()]

while True:
    user_input = input("❯ ")
    response = urllib.request.urlopen(
        "https://api.anthropic.com/v1/messages",
        data=json.dumps({
            "model": "claude-3-5-sonnet-20241022",
            "max_tokens": 1024,
            "messages": [{"role": "user", "content": user_input}],
            "tools": make_schema()
        }).encode()
    )
    print(response.read())
```

**30 lines. Working agent.**

## Key Principles

### 1. Dictionary-Based Parameters

API returns `tool_use.input` as JSON object → pass as dict:

```python
args = block["input"]  # Already a dict!
result = tool(args)
```

### 2. Schema as Source of Truth

Generate from definition, never write twice:

```python
TOOLS = {"tool": (desc, {"param": "type?"}, fn)}
# Schema auto-generates
```

### 3. Agentic Loop

Keep calling until no more tool uses:

```python
while True:
    response = call_api(messages)
    tool_results = [execute(t) for t in response["tool_uses"]]

    if not tool_results:
        break  # Exit condition

    messages.append({"role": "user", "content": tool_results})
```

## Complete Working Example

**nanocode** - Full Claude Code alternative in 270 lines:

- Location: `examples/nanocode.py`
- Tools: read, write, edit, glob, grep, bash
- Zero dependencies (Python stdlib only)
- Supports Anthropic API + OpenRouter

See: [examples/nanocode.md](examples/nanocode.md)

## Common Patterns

### Add New Tool

```python
def my_tool(args):
    return process(args["input"])

TOOLS["my_tool"] = (
    "Description of what tool does",
    {"input": "string", "optional": "number?"},
    my_tool,
)
```

### Optional Parameters

```python
def read(args):
    offset = args.get("offset", 0)  # Default 0
```

Mark with `?`: `{"offset": "number?"}`

### Error Handling

```python
def run_tool(name, args):
    try:
        return TOOLS[name][2](args)
    except Exception as err:
        return f"error: {err}"
```

## Advanced Topics

**Multi-step reasoning**: [references/multi-step-reasoning.md](references/multi-step-reasoning.md)

**Tool composition**: [references/tool-composition.md](references/tool-composition.md)

**State management**: [references/state-management.md](references/state-management.md)

**Troubleshooting**: [references/troubleshooting.md](references/troubleshooting.md)

