---
title: "Ejecutar un comando en el espacio de trabajo"
description: "Ejecuta un único comando de shell en una copia de trabajo del borrador del sitio, dentro de su propio contenedor."
canonical: "https://atelier201.com/docs/es/api/workspace/run"
updated: "2026-11-06"
---

# Ejecutar un comando en el espacio de trabajo

Requiere `sites:write`. No consume créditos. La ruta termina en `/workspace:run`.

El espacio de trabajo es un shell en una copia de trabajo del borrador del sitio, dentro del contenedor propio del sitio y sin conexión. Úsalo para las tareas en las que un shell funciona bien: `rg`, `grep`, `find`, `cat`, `sed -i`, `node` y `npx astro build` para probar una compilación en segundos. El comando se ejecuta en la raíz del proyecto como usuario sin privilegios, y no hay conexión de red.

Los cambios que realiza el comando quedan sin confirmar. La respuesta enumera esos cambios en `uncommitted`, uno por línea, con el formato de `git status` (`M src/pages/index.astro`). No se incorporan al historial hasta que [confirmes los cambios del espacio de trabajo](/docs/api/workspace/commit), y los visitantes no verán nada hasta que publiques.

`command` puede tener un máximo de 8000 caracteres. `timeout_ms` debe estar entre 1000 y 300000, y su valor predeterminado es 60000: si el comando sigue ejecutándose al llegar a ese límite, se detiene y `timed_out` es `true`. Si un comando falla, no se considera un error de API: la llamada se completa correctamente y `exit_code` no es 0. `output` contiene stdout y stderr juntos; si supera los 8 KB, conserva el principio y el final, y `truncated` es `true`.

El espacio de trabajo sigue al borrador. Si otro cambio ha modificado el borrador desde tu último comando, se conservan tus cambios sin confirmar y `note` lo indica. Ocurre lo mismo si ha sido necesario reconstruir el espacio de trabajo.

Un sitio que todavía se está creando responde con `result_not_ready`; un sitio suspendido o en proceso de eliminación responde con `conflict`.

```http
POST https://api.atelier201.com/v1/sites/{site_id}/workspace:run
```

## Authorizations

- `Authorization` (bearer, in header, required)

## Path parameters

- `site_id` (`string`, required): El ID del sitio o su slug (la dirección antes de .atelier201.page).

## Body

`application/json`, required

- `command` (`string`, required, length: `1–8000 chars`): Un comando de bash, ejecutado en la raíz del proyecto sobre una copia de trabajo del borrador: rg, grep, sed, find, cat, node... Sin acceso a la red. Los archivos que modifica quedan sin confirmar hasta ejecutar workspace:commit, que los compila y comunica cualquier error de compilación. Aquí se rechaza la compilación del proyecto: tardaba 30 s y duplicaba esa compilación.
- `timeout_ms` (`integer`, range: `1000–300000`): Valor predeterminado: 60000. El comando se detiene al superar este límite.

## Response

**200**: Ejecuta un comando de shell en el espacio de trabajo del sitio

- `data` (`object`, required)
- `data.revision` (`string`, required, length: `40–40 chars`): La revisión del borrador desde la que se inició el espacio de trabajo.
- `data.exit_code` (`integer`, required, range: `-9007199254740991–9007199254740991`)
- `data.timed_out` (`boolean`, required)
- `data.output` (`string`, required): stdout y stderr juntos; si supera 8 KB, se muestran el principio y el final.
- `data.truncated` (`boolean`, required)
- `data.uncommitted` (`string[]`, required): Los cambios del espacio de trabajo que siguen sin confirmar después del comando, con el formato de git status ("M src/pages/index.astro").
- `data.note` (`string,null`, required): Se indica si el espacio de trabajo se reconstruyó o se actualizó a un borrador más reciente antes de ejecutar el comando.
- `request_id` (`string`, required)

```json
{
  "data": {
    "revision": "<string>",
    "exit_code": 123,
    "timed_out": true,
    "output": "<string>",
    "truncated": true,
    "uncommitted": [
      "<string>"
    ],
    "note": null
  },
  "request_id": "<string>"
}
```

**400**: Códigos posibles: invalid_request, unknown_field, invalid_parameter, invalid_cursor

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**401**: Códigos posibles: authentication_required, invalid_api_key, api_key_expired, api_key_revoked

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**402**: Códigos posibles: insufficient_credits

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**403**: Códigos posibles: insufficient_scope, feature_not_available, admin_required

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**404**: Códigos posibles: resource_not_found

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**409**: Códigos posibles: conflict, result_not_ready, idempotency_key_reused

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**410**: Códigos posibles: result_expired

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**413**: Códigos posibles: request_too_large

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**422**: Códigos posibles: request_too_large_for_plan

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**429**: Códigos posibles: rate_limited

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**500**: Códigos posibles: internal_error

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**503**: Códigos posibles: service_unavailable

- `error` (`object`, required)
- `error.type` (`string`, required)
- `error.code` (`string`, required)
- `error.message` (`string`, required)
- `error.param` (`string`)
- `error.docs_url` (`string`, required)
- `error.action_url` (`string<uri>`)
- `error.details` (`Record<string, object>`)
- `request_id` (`string`, required)

```json
{
  "error": {
    "type": "<string>",
    "code": "<string>",
    "message": "<string>",
    "param": "<string>",
    "docs_url": "<string>",
    "action_url": "<string>",
    "details": {}
  },
  "request_id": "<string>"
}
```

**Example request**

```bash
curl --request POST \
  --url 'https://api.atelier201.com/v1/sites/<site_id>/workspace:run' \
  --header 'Authorization: <api-key>' \
  --header 'Content-Type: application/json' \
  --data '{
  "command": "<string>"
}'
```
