Capítulo 1: El Manifiesto de Cero Magia
Si has intentado construir una aplicación de IA en los últimos dos años, probablemente ya has sentido la Framework Fatigue.
Instalas una biblioteca popular. Importas un ReasoningEngine. Llamas a .run(). Funciona como por arte de magia en el ejemplo de “Hello World”. Pero en el momento en que intentas hacer algo real —como editar una línea específica en un archivo Python sin borrar los imports— se rompe.
Y como usaste un framework, no puedes arreglarlo. Te quedas atascado escarbando entre capas de clases abstractas, patrones de factoría y “Chains” tratando de encontrar el único prompt que está causando la alucinación.
No vamos a hacer eso aquí.
Este libro es una rebelión contra la “Magia.” Vamos a adoptar el enfoque de “Cero Magia”: construir un agente de codificación de nivel productivo llamado Nanocode en Python puro. Sin LangChain, sin AutoGPT, sin Pydantic.
¿Por qué? Porque un agente autónomo no es magia. Es simplemente un bucle while.
¿Qué es realmente un Agente?
Quita el marketing del capital de riesgo, y un “Agente” no es más que un termostato.
Un termostato lee la temperatura (entrada), la compara con el objetivo (decisión) y enciende el calentador (acción). Luego espera y repite. Eso es todo. Un agente de IA hace lo mismo, solo que con texto en lugar de temperatura.

Más en concreto, un agente tiene cuatro partes. El Cerebro es el LLM —una función sin estado donde envías texto y te devuelve texto. Llama a Herramientas —funciones como Leer Archivo y Ejecutar Comando— para interactuar con el mundo exterior. Todo esto vive dentro de un Bucle (un while True) que sigue iterando hasta que la tarea está completa, con la Memoria —simplemente una lista de Python— acumulando el historial de conversación en el proceso. (La lista desaparece cuando el programa termina; añadiremos almacenamiento persistente en el Capítulo 6.)
Si sabes escribir un bucle while, puedes construir un agente.
Al construirlo desde cero, tendrás algo que los usuarios de frameworks no tienen: control. Cuando nuestro agente se quede atascado en un bucle, sabrás exactamente qué línea de código lo causó. Cuando la factura de la API sea demasiado alta, verás exactamente dónde se están filtrando los tokens.
Qué Estamos Construyendo
Nanocode es una herramienta CLI que se ejecuta en tu terminal. Le hablas como a un colega. Lee tus archivos. Ejecuta tus comandos. Edita tu código.
Al final de este libro, lo habrás conectado a Claude Sonnet 4.6 (o DeepSeek, o un modelo local mediante Ollama). Le darás manos —herramientas para leer archivos, escribir archivos y ejecutar comandos de shell— y ojos para buscar en tu base de código. Y construirás un arnés de seguridad para que no pueda hacer accidentalmente rm -rf /.
Configuración del Proyecto
1. Inicializar el Proyecto
1 mkdir nanocode
2 cd nanocode
3 git init
2. Crear un entorno virtual
Nunca instales herramientas de IA de forma global. Entran en conflicto con los paquetes del sistema.
1 # Mac/Linux
2 python3 -m venv venv
3 source venv/bin/activate
4
5 # Windows
6 python -m venv venv
7 venv\Scripts\activate
3. Instalar dependencias
Solo necesitamos tres bibliotecas:
requests— Para comunicarse con las APIs de LLM.python-dotenv— Para cargar las claves de API desde un archivo.env.pytest— Para probar nuestro código sin realizar llamadas a la API.
Crea requirements.txt:
1 requests
2 python-dotenv
3 pytest
Instalar:
1 pip install -r requirements.txt
4. Asegura tus claves
![]() |
Advertencia: Si subes tu clave de API a GitHub, los bots la extraerán y vaciarán tu cuenta en cuestión de minutos. |
Crea .gitignore:
1 .env
2 __pycache__/
3 venv/
4 .DS_Store
5 .nanocode/
La Excepción AgentStop
Antes de escribir el bucle de eventos, necesitamos un mecanismo de salida limpio. Una excepción es mejor que tener sentencias break dispersas por el código.
El contexto: Las excepciones no son solo para errores; también son un mecanismo de flujo de control. Cuando el usuario escribe /q, lanzamos AgentStop. El bucle principal la captura y termina de forma limpia.
El código:
1 # --- Exceptions ---
2
3 class AgentStop(Exception):
4 """Raised when the agent should stop processing."""
5 pass
Esto va al principio de nanocode.py. Es una excepción marcadora—sin lógica, solo una señal.
La Clase Agent
Ahora la abstracción central: la clase Agent. Almacena estado y lógica en un solo lugar, lo que facilita las pruebas.
El Contexto: Podríamos poner toda la lógica en main(). Pero entonces tendríamos que simular input() y print() para probarla. Al extraer la lógica en Agent.handle_input(), podemos probarla directamente.
El Código:
10 class Agent:
11 """A coding agent that processes user input."""
12
13 def __init__(self):
14 pass
15
16 def handle_input(self, user_input):
17 """Handle user input. Returns output string, raises AgentStop to quit."""
18 if user_input.strip() == "/q":
19 raise AgentStop()
20
21 if not user_input.strip():
22 return ""
23
24 return f"You said: {user_input}\n(Agent not yet connected)"
El recorrido del código:
- Líneas 13-14: Constructor vacío por ahora. Añadiremos
brainytoolsen capítulos posteriores. - Líneas 18-19: El comando
/qlanzaAgentStopen lugar de devolver un valor especial — quien llama decide cómo gestionar el cierre. - Línea 24: Repite la entrada tal cual. Es un marcador de posición — más adelante, enviaremos esto al Brain.
Definir el éxito mediante pruebas
Antes de escribir el bucle principal, necesitamos pruebas.
Crea test_nanocode.py:
1 import pytest
2 from nanocode import Agent, AgentStop
3
4
5 def test_handle_input_returns_string():
6 """Verify handle_input returns a string for normal input."""
7 agent = Agent()
8 result = agent.handle_input("hello")
9 assert isinstance(result, str)
10 assert "hello" in result
11
12
13 def test_empty_input_returns_empty_string():
14 """Verify empty/whitespace input returns empty string."""
15 agent = Agent()
16 assert agent.handle_input("") == ""
17 assert agent.handle_input(" ") == ""
18 assert agent.handle_input("\n") == ""
19
20
21 def test_quit_command_raises_agent_stop():
22 """Verify /q raises AgentStop exception."""
23 agent = Agent()
24 with pytest.raises(AgentStop):
25 agent.handle_input("/q")
26
27
28 def test_quit_command_with_whitespace():
29 """Verify /q works with surrounding whitespace."""
30 agent = Agent()
31 with pytest.raises(AgentStop):
32 agent.handle_input(" /q ")
Ejecuta las pruebas:
1 pytest test_nanocode.py -v
1 test_nanocode.py::test_handle_input_returns_string PASSED
2 test_nanocode.py::test_empty_input_returns_empty_string PASSED
3 test_nanocode.py::test_quit_command_raises_agent_stop PASSED
4 test_nanocode.py::test_quit_command_with_whitespace PASSED
Todo en verde. Nuestro agente maneja correctamente los casos básicos.
![]() |
Aparte: ¿Por qué pytest? Descubre funciones que comienzan con |
El Bucle Principal
Ahora la envoltura de E/S ligera que conecta el agente con la terminal:
29 def main():
30 agent = Agent()
31 print("⚡ Nanocode v0.1 initialized.")
32 print("Type '/q' to quit.")
33
34 while True:
35 try:
36 user_input = input("\n❯ ")
37 output = agent.handle_input(user_input)
38 if output:
39 print(output)
40
41 except (AgentStop, KeyboardInterrupt):
42 print("\nExiting...")
43 break
44
45
46 if __name__ == "__main__":
47 main()
El recorrido:
- Líneas 30-32: Crea el agente e imprime los mensajes de inicio.
- Línea 36:
input()bloquea la ejecución y espera a que el usuario escriba algo. - Líneas 37-39: Llama a
handle_input()e imprime cualquier salida. - Líneas 41-43: Captura
AgentStop(desde/q) oKeyboardInterrupt(desde Ctrl+C) y sale del bucle.
![]() |
Aparte: La función |
Observa la separación: Agent.handle_input() contiene toda la lógica. main() es simplemente el pegamento de E/S. Esto hace que el agente sea testeable sin simular stdin/stdout.
Ejecútalo
1 python nanocode.py
Deberías ver:
1 ⚡ Nanocode v0.1 initialized.
2 Type '/q' to quit.
3
4 ❯ hello
5 You said: hello
6 (Agent not yet connected)
7
8 ❯ /q
9
10 Exiting...
Este es el chasis. El motor viene a continuación.
Concluyendo
Eso es el chasis: una clase Agent, un método handle_input(), un bucle while True. Todavía no hace nada útil—pero todo lo que construyamos a partir de aquí encaja en este esqueleto. Las pruebas garantizan que no rompamos lo que ya funciona conforme avanzamos.

