---
title: "Herramientas"
description: "Un módulo de herramientas se ejecuta en cada entorno de agente. beeuni.yaml enumera las herramientas de Beeuni y las herramientas propias del proyecto, y la lista de herramientas de cada agente determina quién puede usarlas."
---

Una herramienta es una función que el modelo llama durante un turno. Una
[sesión](/docs/es/work/sessions) tiene tres tipos, en ambos
[arneses](/docs/es/work/harnesses), harness estándar y harness experimental:

| Tipo | Nombres | Implementado por |
| --- | --- | --- |
| Herramientas del arnés | `bash`, `read`, `write`, `edit`, `glob`, `grep`, `task`, `question`, … | El arnés. |
| Herramientas de Beeuni | `web_search`, `image_search`, `scrape_webpage`, `memory`, `show` | Beeuni. `beeuni.yaml` enumera cada una como `<name>: beeuni:<name>`. Si un proyecto no tiene la clave `tools:`, obtiene las cinco. |
| Herramientas del proyecto | Cualquier nombre que declares | Tu proyecto: un módulo, declarado bajo `tools:` en `beeuni.yaml`. |

Las herramientas de Beeuni y las del proyecto son independientes del arnés. El daemon del entorno aislado carga un módulo por herramienta y lo ejecuta en cualquiera de los dos arneses, con el mismo nombre, argumentos y resultado. harness experimental llama al módulo en el proceso del daemon. harness estándar lo llama mediante un complemento que escribe el daemon y que reenvía cada llamada al daemon. Un módulo nunca importa un paquete de arnés.

<a id="beeuni-tools-in-beeuniyaml"></a>

## Herramientas de Beeuni en beeuni.yaml

Un proyecto nuevo enumera las cinco herramientas de Beeuni bajo `tools:`:

```yaml
tools:
  web_search: beeuni:web_search      # maintained by Beeuni, updated automatically
  image_search: beeuni:image_search
  scrape_webpage: beeuni:scrape_webpage
  memory: beeuni:memory
  show: beeuni:show
  # lookup_order: tools/lookup_order.ts   # your own tool: a module in your repo
```

`beeuni:<name>` significa: la herramienta que mantiene Beeuni. Una corrección se aplica a todos los proyectos que la enumeran, sin que estos tengan que cambiar nada.

<a id="which-beeuni-tools-a-session-gets"></a>

### Qué herramientas de Beeuni obtiene una sesión

| `beeuni.yaml` | La sesión obtiene |
| --- | --- |
| No hay clave `tools:`, ni en el archivo raíz ni en ningún archivo [importado](/docs/es/project/manifest#imports) | Las cinco herramientas de Beeuni. Un proyecto creado antes de que existiera esta lista las conserva todas. |
| Hay una clave `tools:`, aunque esté vacía (`tools: {}`, o `tools:` con todas las líneas eliminadas) | Solo las herramientas de Beeuni que enumere, como `beeuni:<name>` o como un módulo que reemplace la herramienta. |

En ambos casos se cargan las herramientas propias del proyecto.

<a id="see-what-a-session-gets"></a>

### Consultar qué obtiene una sesión

`beeuni tools ls` lee `beeuni.yaml` y sus importaciones, e imprime cada herramienta que obtiene una sesión y, después, las herramientas de Beeuni que el proyecto quitó:

```text
$ beeuni tools ls
NAME            KIND                 SOURCE
web_search      beeuni (overridden)  tools/web_search.ts
scrape_webpage  beeuni               beeuni:scrape_webpage
memory          beeuni               beeuni:memory
show            beeuni               beeuni:show
lookup_order    project              tools/lookup_order.ts

Removed Beeuni tools: image_search
Add `<name>: beeuni:<name>` under `tools:` to get one back.
```

| Tipo | Significado |
| --- | --- |
| `beeuni` | Una herramienta de Beeuni, enumerada como `beeuni:<name>` (o todas, si no hay clave `tools:`). |
| `beeuni (overridden)` | Un nombre de herramienta de Beeuni con una ruta de módulo: se ejecuta el módulo del proyecto en su lugar. |
| `project` | Una herramienta propia del proyecto. |

`beeuni tools ls --json` imprime `{ manifest, tools_key, tools: [{ name, kind, source }], removed }`.

<a id="remove-a-beeuni-tool"></a>

### Quitar una herramienta de Beeuni

Elimina su línea bajo `tools:`. Todos los agentes del proyecto pierden la herramienta, en ambos arneses y en todas las sesiones que comiencen después de que se integre la solicitud de cambio. Para conservar una herramienta para un solo agente, usa [`agents.<name>.tools`](#who-may-use-which-tool).

En una sesión de un proyecto que quitó una herramienta:

- **harness estándar** no ofrece la herramienta al modelo.
- **harness experimental** no ofrece la herramienta. Si se la llama, falla con `Tool show not found`
  (para `show`).
- **El daemon** responde `POST /beeuni/tools/<name>` con `404` y
  `no tool named <name> is loaded`.
- **Una habilidad que mencione la herramienta se sigue cargando.** Por ejemplo, `beeuni-memory` menciona `memory`. El modelo lee la habilidad, no encuentra esa herramienta y usa otras: si no tiene `memory`, lee y edita los archivos de `memory/` con las herramientas de archivos.

<a id="change-a-beeuni-tool-eject"></a>

### Cambiar una herramienta de Beeuni: copiarla al proyecto

`beeuni tools eject <name>` crea una copia propia de una herramienta de Beeuni en el proyecto:

```text
$ beeuni tools eject web_search
  ✓  Ejected web_search
  wrote   tools/web_search.ts (the Beeuni source, now the project's to change)
  set     beeuni.yaml: tools.web_search: tools/web_search.ts

Next:
  1. Edit tools/web_search.ts. Keep the default export: { description, parameters, execute(args, context) }.
  2. beeuni validate
  3. git add tools/web_search.ts beeuni.yaml && git commit -m "Own the web_search tool"
  4. Open a change request: git push origin HEAD && beeuni cr open --title "Own the web_search tool"
Sessions load the copy after the change request merges.
```

- Escribe el código fuente de Beeuni —los mismos bytes que ejecuta el entorno aislado— en `tools/<name>.ts`. El archivo solo importa módulos `node:*` y lee `BEEUNI_API_URL`, `BEEUNI_TOKEN` y las claves del proveedor desde `context.env`, por lo que funciona tal cual.
- Establece `<name>: tools/<name>.ts` en `beeuni.yaml`, en el archivo que declara la entrada (el archivo raíz o uno importado). Conserva todas las demás líneas y comentarios. La línea modificada termina en `# ejected from beeuni:<name>`.
- Si no hay una clave `tools:`, la crea y enumera las otras cuatro herramientas de Beeuni como `beeuni:<name>`, de modo que la copia no quita ninguna.
- No continúa si existe `tools/<name>.ts` o si la herramienta ya apunta a otro módulo. `--force` sobrescribe.
- No continúa si el nombre no corresponde a una herramienta de Beeuni.

La copia es tuya. Beeuni ya no la actualiza. Para volver a la herramienta mantenida, cambia la línea a `<name>: beeuni:<name>` y elimina el archivo.

<a id="override-without-eject"></a>

### Reemplazar sin copiar

Un nombre de herramienta de Beeuni con una ruta de módulo reemplaza la herramienta de Beeuni en todos los arneses:

```yaml
tools:
  web_search: integrations/search/web_search.ts
```

<a id="the-web-ui-views"></a>

### Vistas de la interfaz web

La interfaz web tiene una vista para cada herramienta de Beeuni, seleccionada por el nombre de la herramienta. Las vistas `show` y `memory` leen los argumentos de la llamada (`type`, `path`, `url`,
`content`, `items`; `command`, `path`). Las vistas `web_search`, `image_search` y
`scrape_webpage` leen el JSON de salida. Una copia modificada que conserve el nombre debe mantener esos argumentos y esa estructura de salida; de lo contrario, la interfaz muestra la salida sin procesar.

<a id="validation"></a>

### Validación

`beeuni validate` comprueba la lista:

- `<name>` en `beeuni:<name>` debe ser una herramienta de Beeuni, y la clave debe coincidir con ella. `web_search: beeuni:image_search` es un error:
  ``must be `beeuni:web_search` (the Beeuni tool) or a repo-relative path to a .ts or .js module (e.g. `tools/web_search.ts`) that replaces it.``
- Una clave `tools:` que no enumere ninguna herramienta de Beeuni genera una advertencia:
  ``Sessions of this project get no Beeuni tool (web_search, image_search, scrape_webpage, memory, show). Add `<name>: beeuni:<name>` to keep one.``
  Esto detecta si un proyecto añade su primera herramienta propia y, por accidente, elimina las cinco de Beeuni.
- Si `tools` de un agente incluye una herramienta de Beeuni que el proyecto no carga, se genera una advertencia: ``"show" is a Beeuni tool this project does not load: add `show: beeuni:show` under the top-level `tools`, or remove it here.``

La [referencia del manifiesto](/docs/es/project/manifest#tools) contiene todas las reglas.

<a id="write-a-project-tool"></a>

## Escribir una herramienta del proyecto

```ts
// tools/lookup_order.ts
export default {
  description: 'Look up an order by id. Returns its status and carrier.',
  parameters: {
    type: 'object',
    properties: {
      id: { type: 'string', description: 'The order id, e.g. "A-1042"' },
      include_items: { type: 'boolean', description: 'Also list the items' },
    },
    required: ['id'],
  },
  async execute(args, context) {
    const response = await fetch(`https://orders.example.com/v1/orders/${args.id}`, {
      headers: { authorization: `Bearer ${context.env.ORDERS_API_KEY}` },
      signal: context.signal,
    })
    if (!response.ok) throw new Error(`orders API answered ${response.status}`)
    return await response.json()
  },
}
```

```yaml
# beeuni.yaml
tools:
  web_search: beeuni:web_search
  # … the other Beeuni tools you keep
  lookup_order: tools/lookup_order.ts
```

La exportación predeterminada es un objeto simple:

| Campo | Regla |
| --- | --- |
| `description` | Cadena no vacía. El modelo la lee para decidir cuándo llamar a la herramienta. |
| `parameters` | [Esquema JSON](https://json-schema.org) de los argumentos, `type: 'object'`. El modelo lo recibe tal cual, así que enumera los argumentos obligatorios en `required`. Beeuni no valida los argumentos con este esquema. |
| `execute(args, context)` | Devuelve una cadena o cualquier valor JSON (enviado como JSON con sangría). Puede ser `async`. Si se lanza un error, este será el error de la herramienta y el modelo leerá su mensaje. |

`context` contiene:

| Campo | Qué es |
| --- | --- |
| `sessionId` | La sesión de Beeuni a la que pertenece la llamada. |
| `agent` | El agente que hizo la llamada. |
| `directory` | La copia de trabajo del proyecto, `/workspace`. Resuelve las rutas relativas con respecto a ella. |
| `env` | El entorno del equipo y los [secretos](/docs/es/project/secrets) que recibe este agente, tal como están ahora. Lee un secreto como `context.env.NAME`: un secreto modificado después del arranque del equipo está en `context.env`, no en `process.env`. |
| `signal` | Un `AbortSignal` que aborta cuando el usuario detiene el turno. Pásalo a `fetch`. |

- **Tamaño de salida.** Una salida de más de 50 KB o 2.000 líneas se guarda completa en un archivo del directorio temporal del sandbox. El modelo recibe el inicio, el tamaño y la ruta del archivo. Devuelve lo que el modelo necesita, no un volcado sin procesar.
- **Errores.** Un error lanzado termina la llamada y el modelo lee el mensaje de error. Lanza un mensaje que indique qué hay que cambiar.
- **Importaciones.** Un módulo puede importar módulos `node:*`, API de Bun y archivos relativos. Un paquete se resuelve desde un `node_modules` junto al módulo o en un directorio superior. El sandbox no instala ningún paquete para una herramienta, y una [versión de configuración](/docs/es/work/runtime#config-convergence) solo contiene los archivos que Git rastrea. Usa `fetch` para las API HTTP. TypeScript se ejecuta sin un paso de compilación.
- **Fallos.** Si un módulo no se carga (falta un archivo, no hay exportación predeterminada, un `parameters` que no es un esquema de objeto, un error durante la importación o un paquete que no se resuelve), se omite y las demás herramientas se siguen cargando. El daemon registra `[tools] project tools that did not load` con el motivo de cada herramienta.

<a id="parameters-with-zod"></a>

### `parameters` con zod

zod 4 genera el mismo esquema JSON:

```ts
import { z } from 'zod'

export default {
  description: 'Look up an order by id.',
  parameters: z.toJSONSchema(z.object({ id: z.string().describe('The order id') })),
  async execute(args) {
    return `order ${args.id}: shipped`
  },
}
```

Este módulo solo se carga cuando `zod` se resuelve desde un `node_modules` en el checkout que ejecuta la sesión. De lo contrario, falla con `Cannot find package 'zod'`.
Para escribir el esquema con zod y distribuir un esquema JSON sin formato, imprímelo una vez y pega el resultado en `parameters`:

```bash
bun -e "import { z } from 'zod'; console.log(JSON.stringify(z.toJSONSchema(z.object({ id: z.string() })), null, 2))"
```

<a id="example-call-an-http-api-with-a-project-secret"></a>

### Ejemplo: llamar a una API HTTP con un secreto del proyecto

Guarda la clave como secreto del proyecto. El comando lee el valor desde la entrada estándar:

```bash
beeuni secrets set WEATHER_API_KEY=-
```

Concede acceso al secreto a los agentes que llaman a la herramienta. El agente `beeuni` del starter tiene `secrets: all`. Un agente con alcance limitado lo indica así: `secrets: [WEATHER_API_KEY]`.

Escribe el módulo:

```ts
// tools/weather_now.ts
export default {
  description: 'Current weather for a city: temperature in °C and conditions.',
  parameters: {
    type: 'object',
    properties: { city: { type: 'string', description: 'City name, e.g. "Berlin"' } },
    required: ['city'],
  },
  async execute(args, context) {
    const key = context.env.WEATHER_API_KEY
    if (!key) throw new Error('WEATHER_API_KEY is not set: run `beeuni secrets set WEATHER_API_KEY=-` and grant it to this agent.')
    const url = `https://api.weather.example.com/v1/current?city=${encodeURIComponent(args.city)}`
    const response = await fetch(url, { headers: { authorization: `Bearer ${key}` }, signal: context.signal })
    if (!response.ok) throw new Error(`weather API answered ${response.status}: ${await response.text()}`)
    const data = await response.json()
    return { city: args.city, temperature_c: data.temp_c, conditions: data.conditions }
  },
}
```

Decláralo:

```yaml
tools:
  # … the Beeuni tools you keep
  weather_now: tools/weather_now.ts
```

<a id="example-override-websearch"></a>

### Ejemplo: reemplazar `web_search`

`beeuni tools eject web_search` escribe `tools/web_search.ts` y establece `web_search: tools/web_search.ts`. Luego modifica el código. Por ejemplo, para conservar solo los resultados de un sitio, añade el sitio a cada consulta en `execute`, antes de la solicitud:

```ts
// tools/web_search.ts, inside execute()
const queries = String(args.query ?? '').split('|||').map((query) => query.trim()).filter(Boolean)
  .map((query) => `site:docs.example.com ${query}`)
```

Conserva el nombre, los argumentos y el JSON de salida para que sigan funcionando las habilidades que usan `web_search` y la vista de la interfaz web.

<a id="test-a-tool"></a>

### Probar una herramienta

`beeuni validate` comprueba el nombre, la ruta, la ausencia de un archivo y los valores de `beeuni:`. `beeuni tools ls` muestra lo que recibe una sesión.

Después, confirma los cambios, haz push y abre una solicitud de cambio. Cuando se integre, inicia una sesión y solicita una llamada con argumentos reales:

```bash
beeuni sessions new --wait --prompt "Call the weather_now tool once with city Berlin and print its output."
```

Una herramienta que no se carga no se ofrece al modelo. Una herramienta que lanza un error responde con el mensaje de error. `beeuni sessions log <id>` imprime los mensajes de la sesión, con cada llamada a una herramienta y su estado.

<a id="declare-tools"></a>

## Declarar herramientas

`tools:` asigna cada nombre de herramienta a su módulo, o un nombre de herramienta de Beeuni a `beeuni:<name>`. Tú eliges la carpeta del módulo.

```yaml
tools:
  web_search: beeuni:web_search
  memory: beeuni:memory
  lookup_order: tools/lookup_order.ts
  crm_note: integrations/crm/note.ts
```

- Los nombres usan snake_case y no pueden superar los 64 caracteres: `^[a-z][a-z0-9_]{0,63}$`.
- Un nombre de herramienta del harness es un error. Para una herramienta de Beeuni, se indica `beeuni:<name>` o la ruta del módulo; el módulo reemplaza la herramienta de Beeuni en todos los harnesses.
- Las rutas son relativas al repositorio y terminan en `.ts`, `.js`, `.mts`, `.mjs`, `.cts` o `.cjs`.
- Los archivos indicados en [`imports:`](/docs/es/project/manifest#imports) pueden declarar herramientas. Si un nombre se declara en dos archivos, se produce un error. Una clave `tools:` en un archivo importado cuenta como clave `tools:` para la regla de selección.

[La referencia del manifiesto](/docs/es/project/manifest#tools) contiene todas las reglas.

<a id="who-may-use-which-tool"></a>

## Quién puede usar cada herramienta

`agents.<name>.tools` decide qué herramientas ve el modelo de un agente. Incluye por igual herramientas del harness, de Beeuni y del proyecto.

```yaml
agents:
  beeuni:
    tools: all                                    # every tool (the default)
  researcher:
    tools: [read, grep, web_search, lookup_order] # only these
  support:
    tools:
      exclude: [bash, write, edit]                # every tool but these
  greeter:
    tools: none                                    # no tool
```

| Valor | Herramientas disponibles para el agente |
| --- | --- |
| Omitido o `all` | Todas las herramientas. |
| `none` | Ninguna herramienta. |
| Una lista | Solo las herramientas incluidas en la lista. Una lista con `*` no es válida: `all`. |
| `{ exclude: [...] }` | Todas las herramientas, excepto las incluidas en la lista. |
| `{ bash: false, … }` | El formato anterior de mapa: `false` excluye una herramienta. |

- `tools` decide la visibilidad. Las reglas `permission` del agente siguen determinando si se permite, se solicita o se deniega una llamada. Una herramienta que no está en la lista se oculta al modelo y se deniega si este intenta llamarla.
- Una lista de agente no puede añadir una herramienta de Beeuni que el proyecto no carga. Primero, inclúyela en el `tools:` de nivel superior.
- Un subagente iniciado con la herramienta `task`: en harness experimental solo obtiene las herramientas permitidas tanto por su propia lista como por la lista del agente de la sesión. En harness estándar obtiene las herramientas de su propia lista: harness estándar aplica las reglas de cada agente solo a ese agente. Para evitar que un agente delegue, no incluyas `task` en su lista.
- Las herramientas de [Connector](/docs/es/connect/connectors) siguen `agents.<name>.connectors`, no esta lista.
- `beeuni validate` advierte si un nombre no corresponde a una herramienta del harness, de Beeuni o del proyecto, y si el proyecto no carga una herramienta de Beeuni. Un error tipográfico en una lista `exclude` hace que la herramienta real siga habilitada.

En harness estándar, `bash` también abarca las herramientas `pty_*` del complemento de terminal, y `write`, `edit` y `apply_patch` comparten un permiso: incluir una muestra las tres y excluir una las oculta todas. harness experimental tiene herramientas `write` y `edit` independientes.

<a id="when-a-change-takes-effect"></a>

## Cuándo se aplica un cambio

Una sesión carga sus herramientas cuando se inicia el entorno de ejecución. Un cambio se aplica una vez integrada la solicitud de cambio: las sesiones nuevas lo cargan y, con las [versiones de configuración](/docs/es/work/runtime#config-convergence), una sesión en curso lo carga en la siguiente convergencia. En harness experimental, los cambios en una herramienta del proyecto o en la lista de herramientas de Beeuni reinician el entorno de ejecución en el mismo lugar cuando no hay ningún turno en curso; la conversación continúa.

<a id="tools-in-harnessesopencodetools"></a>

## Herramientas en `harnesses/opencode/tools/`

harness estándar sigue cargando herramientas personalizadas desde su directorio de configuración. harness experimental no lo hace. Los proyectos creados antes de que hubiera herramientas alojadas incluyen copias de las herramientas de Beeuni allí (`web_search.ts`, `memory.ts`, …).

- En harness estándar, una herramienta de esa carpeta prevalece sobre la herramienta alojada con el mismo nombre, así que el proyecto conserva su copia hasta que se elimine. Elimina las copias de las herramientas de Beeuni: el daemon aloja las que indica `beeuni.yaml`, en ambos harnesses.
- Para que una herramienta de harness estándar funcione en ambos harnesses, muévela fuera de la carpeta, reemplaza `tool({ description, args, execute })` por un objeto simple cuyo `parameters` sea un esquema JSON, lee los secretos desde `context.env` y declárala en `tools:`.
