Scripts y comandos dentro de un skill
Scripts y comandos dentro de un skill
Un skill no está obligado a limitarse a prosa. La especificación reconoce un
directorio convencional scripts/ que, en sus propias palabras, “contains
executable code that agents can run”. Este capítulo cubre las tres formas de meter
ejecución en un skill —comando puntual, script empaquetado y script autocontenido
con sus dependencias inline—, cómo diseñar la interfaz para que un agente la use
sin equivocarse, y dónde termina la responsabilidad del estándar en materia de
seguridad. Si aún no tienes claro el esqueleto de un skill, revisa
Anatomía de un skill y
La especificación al detalle.
Qué dice la especificación sobre scripts/
Muy poco, y conviene saber exactamente cuánto. El texto normativo completo es:
Contains executable code that agents can run. Scripts should:
- Be self-contained or clearly document dependencies
- Include helpful error messages
- Handle edge cases gracefully
Supported languages depend on the agent implementation. Common options include Python, Bash, and JavaScript.
De ahí salen tres hechos y ni uno más: scripts/ es una convención opcional
—un directorio de skill PUEDE (may) contener cualquier archivo más allá del
SKILL.md obligatorio, y “the conventions below are recommendations”—; los
scripts DEBERÍAN (should, en minúscula en el original: la spec no declara
adherencia a RFC 2119) ser autocontenidos o documentar sus dependencias, incluir
mensajes de error útiles y manejar casos límite, que son las tres únicas
afirmaciones normativas sobre scripts; y los lenguajes soportados dependen de la
implementación del agente, con Python, Bash y JavaScript como opciones comunes,
no como lista cerrada.
Todo lo demás en este capítulo procede de la guía oficial Using scripts, que es guía de autoría, no norma. Un skill que la ignore sigue siendo válido.
Cuándo un script y cuándo prosa
La prosa le dice al agente qué hacer y lo deja razonar; el script le da un procedimiento congelado y cambia qué parte del trabajo es reproducible.
flowchart TD
A["Necesito que ocurra algo concreto<br/>durante la ejecución del skill"] --> B{"¿Existe ya un paquete<br/>que lo hace?"}
B -->|"Sí"| C{"¿Basta invocarlo<br/>con unos pocos flags?"}
C -->|"Sí"| D["Comando puntual en SKILL.md<br/>con la versión fijada"]
C -->|"No, el comando crece"| E["Script probado en scripts/"]
B -->|"No"| F{"¿El agente reinventa<br/>la misma lógica cada vez?"}
F -->|"Sí"| E
F -->|"No, varía por caso"| G{"¿La operación es frágil,<br/>destructiva o exige un orden?"}
G -->|"Sí"| E
G -->|"No"| H["Instrucciones en prosa<br/>en SKILL.md"]
La guía de buenas prácticas llama a esto bundling reusable scripts: si al
comparar trazas ves que el agente reinventa la misma lógica en cada corrida,
escribe el script una vez, pruébalo y empaquétalo. Sobre los comandos puntuales
dice literalmente: “when a command grows complex enough that it’s hard to get
right on the first try, a tested script in scripts/ is more reliable”. El
criterio inverso también vale: si la tarea admite varios enfoques legítimos y el
agente los resuelve bien, un script solo le quita margen — ese es el eje de
Escribir buenas instrucciones.
Comandos puntuales sin scripts/
Cuando un paquete existente ya hace el trabajo, se referencia directo en
SKILL.md sin crear ningún directorio; varios ecosistemas resuelven dependencias
en tiempo de ejecución:
| Ejecutor | Ejemplo documentado | Notas de la guía |
|---|---|---|
uvx | uvx [email protected] check . | No viene con Python, requiere instalar aparte. Rápido, cachea agresivamente. |
pipx | pipx run 'black==24.10.0' . | Alternativa madura a uvx, con mayor disponibilidad en gestores de paquetes del sistema. |
npx | npx eslint@9 --fix . | Viene con Node.js, no hace falta instalar nada extra. |
bunx | bunx eslint@9 --fix . | Reemplazo directo de npx; solo apropiado cuando el entorno tiene Bun en vez de Node.js. |
deno run | deno run --allow-read npm:eslint@9 -- --fix . | Los flags de permiso son obligatorios para acceso a disco o red. Usa -- para separar los flags de Deno de los de la herramienta. |
go run | go run golang.org/x/tools/cmd/[email protected] . | Integrado en el comando go, sin herramientas adicionales. |
Tres consejos que la guía marca explícitamente: fija las versiones
(npx [email protected]) para que el comando se comporte igual con el paso del tiempo;
declara los prerrequisitos en el SKILL.md —“Requires Node.js 18+”— en vez de
asumir que el entorno del agente los tiene, y para requisitos de nivel runtime usa
el campo opcional compatibility, que admite hasta 500 caracteres aunque la spec
advierta que “most skills do not need the compatibility field”; y mueve a un
script los comandos complejos.
Cómo se referencian y ejecutan los scripts
La regla de resolución de rutas es normativa, en la sección File references de la spec: “When referencing other files in your skill, use relative paths from the skill root”. La guía de scripts lo repite: “Use relative paths from the skill directory root to reference bundled files. The agent resolves these paths automatically — no absolute paths needed.”
Nunca escribas rutas absolutas ni ~/.agents/skills/mi-skill/scripts/x.sh dentro
de un SKILL.md. El cliente conoce el directorio base del skill (el padre del
SKILL.md) y resuelve contra él; la guía de implementadores lo describe desde el
otro lado: “resolve them against the skill’s directory (the parent of SKILL.md)
and use absolute paths in tool calls”. La spec añade: “Keep file references one
level deep from SKILL.md”.
Dos pasos: anunciar y luego ordenar
Anunciar los scripts hace que el agente sepa que existen; ordenar su ejecución hace que los use. La guía separa ambos pasos:
## Available scripts
- **`scripts/validate.sh`** — Validates configuration files
## Workflow
1. Run the validation script:
```bash
bash scripts/validate.sh "$INPUT_FILE"
```
Fíjate en un detalle práctico: los ejemplos oficiales invocan a través del
intérprete (bash scripts/..., python3 scripts/...), no como ./scripts/....
La especificación no dice nada sobre permisos de archivo ni sobre el bit de
ejecución, e invocar por intérprete evita depender de él.
La misma convención funciona en archivos de apoyo: “script execution paths (in
code blocks) are relative to the skill directory root, because the agent runs
commands from there”. Aunque el bloque de código viva en references/api.md, la
ruta se escribe scripts/foo.sh, no ../scripts/foo.sh. Los archivos de apoyo
son el tema de
Referencias, plantillas y progressive disclosure avanzada.
Scripts autocontenidos: dependencias declaradas inline
La spec pide que los scripts sean “self-contained or clearly document dependencies”; varios lenguajes permiten cumplir la primera opción sin manifiesto externo ni paso de instalación.
Python con PEP 723 — bloque TOML entre marcadores # /// al inicio:
# /// script
# dependencies = ["beautifulsoup4>=4.12,<5"]
# ///
from bs4 import BeautifulSoup
uv run scripts/extract.py crea un entorno aislado, instala las dependencias y
ejecuta; pipx run también soporta PEP 723. Fija versiones con especificadores
PEP 508, acota el intérprete con requires-python y usa uv lock --script para
reproducibilidad total.
Deno — los especificadores npm: y jsr: hacen autocontenido cualquier
script: import * as cheerio from "npm:[email protected]";. Las dependencias se
cachean globalmente y --reload fuerza la recarga. Aviso literal: “Packages with
native addons (node-gyp) may not work”.
Bun — auto-instala paquetes faltantes en tiempo de ejecución y la versión se
fija en la ruta de import (import * as cheerio from "[email protected]";), con una
trampa documentada: “If a node_modules directory exists anywhere up the
directory tree, auto-install is disabled”. El mismo skill puede comportarse
distinto dentro de un proyecto Node que en el directorio del usuario.
Ruby — bundler/inline declara las gemas en el script con un bloque
gemfile do ... end. Sin lockfile, hay que fijar versiones explícitamente
(gem 'nokogiri', '~> 1.16'); un Gemfile o un BUNDLE_GEMFILE en el
directorio de trabajo pueden interferir.
Diseñar la interfaz para un agente, no para una persona
Cuando un agente ejecuta tu script, lee stdout, stderr y el código de salida para decidir el siguiente paso. La interfaz es el canal de comunicación.
flowchart LR
A["SKILL.md<br/>ordena la ejecución"] --> B["Script"]
B --> C["stdout<br/>datos estructurados"]
B --> D["stderr<br/>progreso y avisos"]
B --> E["código de salida<br/>tipo de fallo"]
C --> F["El agente decide<br/>el siguiente paso"]
D --> F
E --> F
Nada de prompts interactivos. La guía lo marca como “a hard requirement of the
agent execution environment”: los agentes operan en shells no interactivos, no
pueden responder a prompts TTY, diálogos de contraseña ni menús de confirmación.
Un script que se bloquea esperando entrada cuelga indefinidamente. Toda la
entrada llega por flags, variables de entorno o stdin. Es una restricción del
entorno de ejecución, no una cláusula del formato. En vez de imprimir
Target environment: _ y quedarse esperando, el script debe fallar con
Error: --env is required. Options: development, staging, production.
--help es la documentación real. “--help output is the primary way an
agent learns your script’s interface”. Una línea de uso, una descripción breve, la
lista de flags con su default y al menos un ejemplo de invocación completa; todo
conciso, porque esa salida entra al contexto del agente junto con el resto del
trabajo. Los dos ejemplos del final del capítulo muestran el formato.
Mensajes de error que reorientan. Un “Error: invalid input” opaco quema un
turno completo. Di qué falló, qué se esperaba y qué probar:
Error: --format must be one of: json, csv, table. Received: "xml".
Salida estructurada, datos y diagnósticos separados. JSON, CSV o TSV antes que
texto libre: son consumibles por el agente y por jq, cut o awk. Una tabla
alineada con espacios —my-service running 2025-01-15— es difícil de parsear
programáticamente; {"name": "my-service", "status": "running"} no tiene
ambigüedad de campos. Y, literal: “send structured data to stdout and progress
messages, warnings, and other diagnostics to stderr”.
Seis consideraciones adicionales
| Consideración | Qué implica |
|---|---|
| Idempotencia | Los agentes reintentan comandos. “Create if not exists” es más seguro que “create and fail on duplicate”. |
| Restricciones de entrada | Rechazar entrada ambigua con un error claro en vez de adivinar. Usar enums y conjuntos cerrados. |
| Soporte de dry-run | Para operaciones destructivas o con estado, --dry-run deja que el agente previsualice qué va a pasar. |
| Códigos de salida con significado | Códigos distintos por tipo de fallo, documentados en el --help para que el agente sepa qué significa cada uno. |
| Defaults seguros | Evaluar si las operaciones destructivas deben exigir flags explícitos como --confirm o --force. |
| Tamaño de salida predecible | ”Many agent harnesses automatically truncate tool output beyond a threshold (e.g., 10-30K characters)”. Por defecto resumen o límite, con flags como --offset; o exigir --output que sea archivo o - para optar por stdout. |
La idempotencia se justifica por el reintento: un agente que no ve salida clara vuelve a lanzar el comando, y si el script falla al segundo intento interpreta ese fallo como un problema real y se desvía a arreglarlo.
Ejemplo completo 1: skill con script en Bash
env-audit/
- SKILL.md
- scripts/
- audit.sh
Contenido de SKILL.md:
---
name: env-audit
description: Compara un archivo .env contra su plantilla .env.example y reporta variables faltantes, vacías y sobrantes. Úsalo cuando el usuario mencione variables de entorno, un .env incompleto, errores de configuración al arrancar la app, o antes de desplegar a un entorno nuevo.
compatibility: Requires bash 4+ and jq
license: Apache-2.0
---
# Auditoría de variables de entorno
## Scripts disponibles
- **`scripts/audit.sh`** — Compara un `.env` con su plantilla y emite JSON por stdout.
## Flujo de trabajo
1. Localiza plantilla y archivo real —por convención `.env.example` y `.env` en
la raíz del repositorio— y ejecuta
`bash scripts/audit.sh --template .env.example --actual .env`.
2. Interpreta el JSON: `missing` son variables de la plantilla ausentes, `empty`
son presentes pero sin valor —causa habitual de fallos al arrancar que no
dicen qué falta— y `extra` son variables no previstas en la plantilla.
3. Si `missing` o `empty` traen elementos, lista al usuario los nombres exactos.
**No inventes valores** ni los deduzcas del código: pídelos.
## Gotchas
- Se ignoran líneas en blanco y las que empiezan por `#`.
- `FOO=""` cuenta como vacío y se reporta en `empty`.
- Códigos de salida: `0` completado, `2` argumentos inválidos, `3` no encontrado.
scripts/audit.sh:
#!/usr/bin/env bash
set -euo pipefail
usage() { cat <<'EOF'
Usage: bash scripts/audit.sh --template FILE --actual FILE
Compara un archivo .env contra su plantilla y emite JSON por stdout.
Options:
--template FILE Plantilla de referencia, por ejemplo .env.example
--actual FILE Archivo real a auditar, por ejemplo .env
Exit codes: 0 ok, 2 argumentos inválidos, 3 archivo no encontrado
EOF
}
TEMPLATE=""; ACTUAL=""
while [[ $# -gt 0 ]]; do
case "$1" in
--template) TEMPLATE="${2:-}"; shift 2 ;;
--actual) ACTUAL="${2:-}"; shift 2 ;;
-h|--help) usage; exit 0 ;;
*) echo "Error: flag desconocido: \"$1\". Usa --help." >&2; exit 2 ;;
esac
done
if [[ -z "$TEMPLATE" || -z "$ACTUAL" ]]; then
echo "Error: --template y --actual son obligatorios." >&2; usage >&2; exit 2
fi
for f in "$TEMPLATE" "$ACTUAL"; do
[[ -f "$f" ]] || { echo "Error: archivo no encontrado: \"$f\"." >&2; exit 3; }
done
claves() { grep -vE '^\s*(#|$)' "$1" | cut -d= -f1 | tr -d '[:space:]' | sort -u; }
lista() { printf '%s' "$1" | jq -R -s 'split("\n") | map(select(length > 0))'; }
MISSING=$(comm -23 <(claves "$TEMPLATE") <(claves "$ACTUAL"))
EXTRA=$(comm -13 <(claves "$TEMPLATE") <(claves "$ACTUAL"))
EMPTY=$(grep -vE '^\s*(#|$)' "$ACTUAL" | grep -E '=\s*("")?\s*$' | cut -d= -f1 | sort -u || true)
jq -n --arg template "$TEMPLATE" --arg actual "$ACTUAL" \
--argjson missing "$(lista "$MISSING")" \
--argjson empty "$(lista "$EMPTY")" \
--argjson extra "$(lista "$EXTRA")" \
'{template: $template, actual: $actual, missing: $missing, empty: $empty, extra: $extra}'
Qué cumple: no pide entrada interactiva, documenta su interfaz con --help,
distingue códigos de salida por tipo de fallo, manda JSON a stdout y los errores a
stderr, y es idempotente porque solo lee.
Ejemplo completo 2: skill con script en Python autocontenido
Misma estructura —csv-profile/SKILL.md más csv-profile/scripts/profile.py—
con dependencias declaradas inline. SKILL.md:
---
name: csv-profile
description: Genera un perfil estadístico de un archivo CSV o TSV — tipos inferidos, nulos, cardinalidad y rangos por columna. Úsalo cuando el usuario tenga un CSV, TSV o export tabular y quiera entenderlo, detectar datos sucios o decidir cómo limpiarlo, aunque no mencione explícitamente "perfilar" ni "estadísticas".
compatibility: Requires uv and network access on first run to install dependencies
metadata:
author: siemprelisto
version: "1.0"
---
# Perfilado de archivos CSV
## Scripts disponibles
- **`scripts/profile.py`** — Perfila un CSV o TSV. Dependencias declaradas
inline con PEP 723; se ejecuta con `uv run`, sin instalación previa.
## Flujo de trabajo
1. Perfila el archivo con `uv run scripts/profile.py --input datos.csv`.
2. Si supera las 50 columnas la salida se recorta: pide el resto añadiendo
`--offset 50`. Si el resultado va a un archivo, usa `--output perfil.json`.
3. Reporta al usuario, en este orden: columnas con más de un 20% de nulos,
columnas con cardinalidad 1 —constantes, candidatas a eliminar— y columnas
cuyo tipo inferido no coincide con lo que su nombre sugiere.
## Gotchas
- El separador se detecta por extensión: `.tsv` usa tabulador y cualquier otra
cosa usa coma. Para un CSV con punto y coma, pasa `--sep ";"`.
- El script lee el archivo entero en memoria: avisa si supera los 500 MB.
scripts/profile.py:
#!/usr/bin/env -S uv run
# /// script
# requires-python = ">=3.11"
# dependencies = ["pandas>=2.2,<3"]
# ///
import argparse, json, sys
from pathlib import Path
import pandas as pd
EXIT_OK, EXIT_BAD_ARGS, EXIT_NOT_FOUND, EXIT_UNPARSEABLE = 0, 2, 3, 4
MAX_COLUMNS = 50
def perfilar(s: pd.Series) -> dict:
perfil = {"dtype": str(s.dtype), "nulos": int(s.isna().sum()),
"pct_nulos": round(float(s.isna().mean()) * 100, 2),
"cardinalidad": int(s.nunique(dropna=True))}
if pd.api.types.is_numeric_dtype(s) and s.notna().any():
perfil["min"], perfil["max"] = float(s.min()), float(s.max())
return perfil
def main() -> int:
p = argparse.ArgumentParser(
prog="scripts/profile.py",
description="Perfila un CSV o TSV: tipos, nulos, cardinalidad y rangos.",
epilog="Exit codes: 0 ok, 2 args inválidos, 3 no encontrado, 4 no parseable.")
p.add_argument("--input", required=True, help="Ruta del archivo a perfilar")
p.add_argument("--sep", default=None, help="Separador explícito, p. ej. ';'")
p.add_argument("--offset", type=int, default=0, help="Primera columna a reportar")
p.add_argument("--output", default="-", help="Archivo de salida, o '-' para stdout")
args = p.parse_args()
ruta = Path(args.input)
if not ruta.exists():
print(f'Error: archivo no encontrado: "{ruta}".', file=sys.stderr)
return EXIT_NOT_FOUND
if args.offset < 0:
print(f"Error: --offset debe ser >= 0. Recibido: {args.offset}", file=sys.stderr)
return EXIT_BAD_ARGS
sep = args.sep or ("\t" if ruta.suffix.lower() == ".tsv" else ",")
try:
df = pd.read_csv(ruta, sep=sep)
except Exception as exc: # noqa: BLE001
print(f'Error: no se pudo parsear "{ruta}" con separador {sep!r}. Detalle: '
f"{exc}. Prueba con --sep para fijar el separador.", file=sys.stderr)
return EXIT_UNPARSEABLE
cols = list(df.columns)[args.offset : args.offset + MAX_COLUMNS]
reporte = {"archivo": str(ruta), "filas": int(len(df)),
"columnas_totales": len(df.columns), "offset": args.offset,
"truncado": args.offset + len(cols) < len(df.columns),
"columnas": {c: perfilar(df[c]) for c in cols}}
salida = json.dumps(reporte, ensure_ascii=False, indent=2)
if args.output == "-":
print(salida)
else:
Path(args.output).write_text(salida, encoding="utf-8")
print(f'Perfil escrito en "{args.output}"', file=sys.stderr)
return EXIT_OK
if __name__ == "__main__":
sys.exit(main())
Este ejemplo añade tres cosas sobre el de Bash: dependencias inline PEP 723 con
versión acotada, control del tamaño de salida con MAX_COLUMNS más --offset y
--output con - para optar por stdout, y un código de salida dedicado al caso
“el archivo existe pero no se puede parsear”, distinto de “no existe” y que lleva
al agente a una acción distinta.
Permisos, herramientas y allowed-tools
Ejecutar un script implica que el cliente permita ejecutar comandos, y ahí hay dos
capas que no conviene confundir. La capa del cliente: la guía de
implementadores recomienda poner el directorio del skill en la allowlist del
sistema de permisos para que leer sus recursos no dispare diálogos de
confirmación; es una recomendación para quien construye el cliente y no cubre la
ejecución de comandos arbitrarios. Y el campo allowed-tools, que la spec
define como “a space-separated string of tools that are pre-approved to run” con
un único ejemplo, allowed-tools: Bash(git:*) Bash(jq:*) Read; está marcado como
experimental y la propia spec advierte que “support for this field may vary
between agent implementations”. No es un sandbox: dice qué está preaprobado, no
qué está prohibido, y no hay gramática definida más allá de ese ejemplo. Qué hace
cada cliente concreto lo vemos en
El ecosistema.
Seguridad: qué garantías NO da el estándar
Un skill con scripts es código de terceros que se ejecuta en tu máquina, con tus credenciales y tus permisos, y frente a eso la especificación ofrece cero mecanismos:
| Garantía que no existe | Estado real |
|---|---|
| Firma o verificación de autoría | No hay ningún proceso de firma definido en la especificación. |
| Sandbox de ejecución | El estándar no define aislamiento de ningún tipo para los scripts. |
| Modelo de permisos | No hay permisos en el formato. allowed-tools es experimental y preaprueba, no restringe. |
| Declaración obligatoria de efectos | compatibility es opcional y describe requisitos de entorno, no lo que el script hace. |
| Registro oficial con revisión | El repositorio del estándar declara que no mantiene un directorio de skills de la comunidad. |
| Versionado o dependencias entre skills | No hay ningún mecanismo documentado. |
| Escaneo de contenido | skills-ref validate comprueba el frontmatter y las convenciones de nombres, nada más. |
Lo único que la documentación aporta en esta dirección son dos consideraciones
para implementadores de clientes, ambas redactadas como sugerencia. La primera,
literal: “Consider gating project-level skill loading on a trust check” — cargar
los skills que vienen dentro de un repositorio solo tras una comprobación de
confianza, porque un repo clonado puede traer un SKILL.md con instrucciones y
scripts que nadie revisó. La segunda es el allowlisting de permisos ya citado.
Consecuencias prácticas:
- Leer antes de instalar. Un skill son archivos de texto: un
SKILL.mdy sus scripts se leen en un minuto. - Desconfiar del
.agents/skills/de un repo clonado. Es la ruta que la guía de clientes propone para interoperabilidad, y por eso el vector más directo: clonas, abres el agente y el skill ya está en el catálogo. - Fijar versiones en todos los ejecutores, y preferir scripts legibles a comandos crípticos. Como autor, no pidas más de lo necesario: si el script solo lee, que solo lea.
Nada de esto lo impone el formato: es higiene que se ejerce en el cliente y en el proceso de instalación, tema de Distribución. Al empaquetar skills junto con servidores MCP en una unidad distribuible las mismas preguntas se multiplican, y eso lo trata el curso hermano Agent Plugins Spec; para ver cómo resuelve estos detalles un catálogo real de más de cien skills, está Google Skills.
Checklist antes de dar por bueno un script
- La ruta en
SKILL.mdes relativa a la raíz del skill, sin../ni rutas absolutas. - El script está anunciado en una sección de scripts disponibles y su ejecución está ordenada explícitamente en el flujo.
- Se invoca a través del intérprete:
bash scripts/x.sh,uv run scripts/x.py. - No hay ninguna ruta de código que espere entrada por TTY.
-
--helpdescribe qué hace, qué flags acepta, qué códigos de salida devuelve y trae al menos un ejemplo. - Los errores dicen qué se recibió y qué se esperaba; los datos van a stdout en formato estructurado y el progreso a stderr.
- Reejecutarlo dos veces seguidas produce el mismo estado final, y la salida tiene un techo previsible o paginación o
--output. - Las dependencias están declaradas inline con versión acotada, o documentadas en
SKILL.mdy, si son de entorno, encompatibility. -
skills-ref validate ./mi-skillpasa sin errores.
Para comprobar que el script además mejora el resultado del agente está Evaluar la calidad de un skill con evals: la corrida con skill contra la corrida sin él.
Resumen
- La especificación dice de
scripts/solo tres cosas: es un directorio opcional con código ejecutable; los scripts DEBERÍAN (should) ser autocontenidos o documentar dependencias, incluir mensajes de error útiles y manejar casos límite; y los lenguajes soportados dependen del agente. - Hay tres niveles de ejecución: comando puntual referenciado en
SKILL.md(uvx,pipx,npx,bunx,deno run,go run), script empaquetado enscripts/, y script autocontenido con dependencias inline —PEP 723 en Python, especificadoresnpm:/jsr:en Deno, versión en el import en Bun,bundler/inlineen Ruby. El comando puntual sirve mientras sea un par de flags; en cuanto cuesta acertarlo a la primera, un script probado es más fiable. - Las rutas se escriben relativas a la raíz del skill, incluso dentro de
archivos de
references/, porque el agente ejecuta desde ahí. - El agente aprende la interfaz por
--helpy decide el siguiente paso leyendo stdout, stderr y el código de salida: datos estructurados a stdout, diagnósticos a stderr, códigos distintos por tipo de fallo. Los prompts interactivos son inaceptables, no por el formato sino porque el agente corre en shells no interactivos y el script quedaría colgado. - Idempotencia, restricciones de entrada,
--dry-run, defaults seguros y tamaño de salida acotado evitan que un reintento del agente rompa algo o que el harness trunque justo lo importante. - El estándar no aporta firma, sandbox, permisos, revisión ni registro
oficial;
allowed-toolses experimental y preaprueba, no restringe. La única defensa documentada es una sugerencia a los clientes: condicionar la carga de skills de proyecto a una comprobación de confianza. Leer el código antes de instalarlo es responsabilidad de quien lo instala.
Siguiente: Referencias, plantillas y progressive disclosure avanzada