Tu primer agente
Este tutorial construye un pequeño asistente de investigación, Scout, paso a paso. Cada paso es un agent.ts completo que puedes ejecutar con npx tsx agent.ts; cada uno añade una capacidad del kit.
Antes de empezar, prepara un proyecto como en Instalación y asegúrate de que la autenticación funciona (CLAUDE_CODE_OAUTH_TOKEN o ANTHROPIC_API_KEY en el entorno).
Paso 1: un chat con un prompt del sistema
import path from "node:path";
import {
buildSessionOptions,
ensureClaudeAuth,
runChatInk,
type AgentSpec,
type BaseSessionConfig,
} from "@falkenslab/agent-kit";
// 1. Who the agent is. Only buildSystemPrompt says something here; the rest is "nothing".
const spec: AgentSpec<BaseSessionConfig> = {
buildSystemPrompt: () => "You are Scout, a concise research assistant. Answer in short paragraphs.",
buildMcpServers: () => ({}),
pluginRoots: () => [],
buildSubagents: () => undefined,
};
// 2. Credentials: offers to create a token if there's none.
await ensureClaudeAuth();
// 3. How it runs: the oversight mode and the folder it works in.
const config: BaseSessionConfig = { mode: "autonomous", projectDir: process.cwd() };
// 4. The chat. With a session opener and runsDir, every run gets its own folder under .run/.
await runChatInk((run) => buildSessionOptions(config, run.dir, spec, { run }), {
runsDir: path.resolve(".run"),
header: { title: "Scout" },
welcomeMessage: "Ask me anything. /exit to leave.",
});
Ejecútalo y tendrás un chat completo: respuestas en streaming con markdown, /exit o Ctrl+C para salir, ↑/↓ y Ctrl+R para el historial, ? para los atajos.
Qué ha pasado:
buildSessionOptions()ha construido lasOptionsdel SDK: el prompt del sistema (más una línea sobre el idioma de respuesta), las herramientas que recibe esta configuración (aquí soloWebFetchyWebSearch), los hooks de seguridad y los ajustes que el kit define siempre.runChatInk()ha llamado a tu abridor con una carpeta de ejecución nueva (.run/2026-09-29T10-15-00-000Z/), ha arrancado la sesión y ha dibujado el chat. Todo lo que ha mostrado el terminal va alsession.logde esa carpeta; la conversación, aconversation.jsonl.
.run/ a .gitignoreLas carpetas de ejecución guardan conversaciones enteras y resultados de herramientas, sin ocultar nada. No las subas nunca al repositorio.
Paso 2: pantalla completa, modo guiado
const config: BaseSessionConfig = { mode: "guided", projectDir: process.cwd() };
await runChatInk((run) => buildSessionOptions(config, run.dir, spec, { run }), {
runsDir: path.resolve(".run"),
header: { title: "Scout", fields: { mode: config.mode } },
mode: config.mode,
fullscreen: true,
welcomeMessage: "Ask me anything. /exit to leave.",
});
fullscreen: trueocupa todo el terminal: el historial se desplaza en su propia vista (RePág/AvPág, la rueda del ratón), el prompt se queda abajo, arrastrar selecciona texto y un clic derecho lo copia.- En modo
guidedel agente recibe una herramientarequest_human_approvaly debe llamarla antes de cualquier cosa visible para otros o difícil de deshacer; en el chat aparece un panel de aprobación. Shift+Tab cambia ainteractive, donde cada llamada a herramienta pregunta primero, y después aplan, donde el agente solo lee y planifica. Consulta Modos.
Paso 3: una herramienta propia
Cada sesión ya tiene unas cuantas herramientas del kit, como current_time y date_math para las fechas (consulta Las herramientas propias del kit). Las tuyas son servidores MCP. Lo más sencillo es un servidor en proceso construido con tool() y createSdkMcpServer(), devuelto desde buildMcpServers():
import { createSdkMcpServer, tool } from "@falkenslab/agent-kit";
import { z } from "zod";
// Metres per unit.
const LENGTHS: Record<string, number> = { mm: 0.001, cm: 0.01, m: 1, km: 1000, in: 0.0254, ft: 0.3048, mi: 1609.344 };
const units = createSdkMcpServer({
name: "units",
version: "1.0.0",
tools: [
tool(
"convert_length",
"Convert a length between units (mm, cm, m, km, in, ft, mi). Use it instead of converting yourself.",
{
value: z.number().describe("The length to convert"),
from: z.enum(["mm", "cm", "m", "km", "in", "ft", "mi"]),
to: z.enum(["mm", "cm", "m", "km", "in", "ft", "mi"]),
},
async ({ value, from, to }) => {
const result = (value * LENGTHS[from]) / LENGTHS[to];
return { content: [{ type: "text" as const, text: `${value} ${from} = ${Number(result.toPrecision(10))} ${to}` }] };
},
{ annotations: { readOnlyHint: true } },
),
],
});
const spec: AgentSpec<BaseSessionConfig> = {
buildSystemPrompt: () => "You are Scout, a concise research assistant. Use the tools for dates and unit conversions.",
buildMcpServers: () => ({ units }),
pluginRoots: () => [],
buildSubagents: () => undefined,
};
Los esquemas de las herramientas usan zod (npm install zod); una herramienta sin parámetros recibe {}. El kit aprueba automáticamente cada herramienta mcp__*, así que el agente puede llamar a mcp__units__convert_length desde el primer momento. Consulta Herramientas y servidores MCP.
Paso 4: notas que sobreviven a la sesión
Activa las extensiones knowledge y sources del kit, cada una con su carpeta: el agente recibe la base de conocimiento, sus propias herramientas, reglas y skills para llevar sus notas como una wiki enlazada, y una carpeta de originales.
import { knowledge, sources } from "@falkenslab/agent-kit";
const spec: AgentSpec<BaseSessionConfig> = {
// …the same as before, plus:
extensions: [
sources({ dir: (config) => path.join(config.projectDir, "sources") }), // originals: readable, never modified
knowledge({ dir: (config) => path.join(config.projectDir, "knowledge") }), // the agent's notes, through the knowledge_* tools
],
};
Una carpeta es una ruta o, como aquí, una función de la configuración de la sesión: la spec sigue siendo la misma aunque cambie projectDir.
Ahora Scout lleva sus notas con las herramientas knowledge_* (buscar, leer, crear, editar, registrar…) y lee los originales de sources/ con Read, pero nunca los modifica (añade ficheros ahí con las herramientas de las fuentes, que nunca sobrescriben, y list_sources junto con knowledge_index le dice qué no se ha ingerido todavía). Prueba /knowledge:ingest después de dejar un PDF en sources/.
Paso 5: reanudar una conversación
Ya está ahí desde el paso 1: arranca con npx tsx agent.ts --continue para retomar la última conversación, o escribe /resume en el chat para elegir una. Consulta Ejecuciones y reanudación.
Paso 6: hazlo tuyo
import { ui } from "@falkenslab/agent-kit";
await runChatInk((run) => buildSessionOptions(config, run.dir, spec, { run }), {
runsDir: path.resolve(".run"),
header: {
title: "Scout",
fields: { mode: config.mode },
art: [ui.accent(" ▄▀▀▄ "), ui.accent(" █ █ "), ui.accent(" ▀▀ ")],
},
mode: config.mode,
fullscreen: true,
promptLabel: `${ui.user("you>")} `,
agentLabel: ui.agent("Scout>"),
firstPromptSuggestion: "what's new in TypeScript this year?",
historyPath: path.resolve(".run/history.jsonl"),
theme: { accent: "#56b6c2", selection: "#56b6c2" },
});
header.art: un pequeño logotipo a la izquierda del título, una cadena por fila, solo con caracteres de una columna.promptLabelyagentLabel: las etiquetas del chat sencillo y del registro de la sesión.firstPromptSuggestion: la sugerencia que se muestra (y que se acepta con Tab) antes del primer turno.historyPath: el historial de ↑/↓, que se conserva entre ejecuciones.theme: solo los colores que quieras cambiar. Consulta Temas.
Adónde ir después
- La forma completa de una spec: AgentSpec.
- Delegar en especialistas: Subagentes.
- Ejecutar sin chat (un trabajo, un script): Ejecuciones de una sola vez.
- Manejar el agente desde una aplicación de escritorio: Hosts a medida.
- Un agente completo para leer: Captain Whiskers.